- Jun 2024
-
www.second.dev www.second.dev
- Sep 2023
-
-
```svelte
<script> let m = { x: 0, y: 0 }; function handleMousemove(event) { m.x = event.clientX; m.y = event.clientY; } </script> <div on:mousemove={handleMousemove}> The mouse position is {m.x} x {m.y} </div> <style> div { width: 100%; height: 100%; } </style>```
```js / React Hook - sample code to capture mouse coordinates/
import React, { useState, useCallback, useEffect, useRef } from 'react';
function useEventListener(eventName, handler, element = window) { // Create a ref that stores handler const savedHandler = useRef();
// Update ref.current value if handler changes. // This allows our effect below to always get latest handler ... // ... without us needing to pass it in effect deps array ... // ... and potentially cause effect to re-run every render. useEffect(() => { savedHandler.current = handler; }, [handler]);
useEffect(() => { // Make sure element supports addEventListener const isSupported = element && element.addEventListener; if (!isSupported) return;
// Create event listener that calls handler function stored in ref const eventListener = event => savedHandler.current(event); // Add event listener element.addEventListener(eventName, eventListener); // Remove event listener on cleanup return () => { element.removeEventListener(eventName, eventListener); }; }, [eventName, element] // Re-run if eventName or element changes
); }
export default function App() { // State for storing mouse coordinates const [coords, setCoords] = useState({ x: 0, y: 0 });
// Event handler utilizing useCallback ... // ... so that reference never changes. const handler = useCallback( ({ clientX, clientY }) => { // Update coordinates setCoords({ x: clientX, y: clientY }); }, [setCoords] );
// Add event listener using our hook useEventListener('mousemove', handler);
return (
The mouse position is ({coords.x}, {coords.y})
); } ```
-
- Aug 2023
-
news.ycombinator.com news.ycombinator.com
-
- Jul 2023
-
blog.logrocket.com blog.logrocket.com
Tags
Annotators
URL
-
-
github.com github.com
-
That is because React.StrictMode renders the component twice (as it is intentional), that causes 2 connections get created. Create a ws connection inside useEffect and close on the effect cleanup would help or remove StrictMode from index file.
It's not a bug, it's a feature - they say.
React DX is so special...
-
-
www.kianmusser.com www.kianmusser.com
-
danielrotter.at danielrotter.at
-
www.builder.io www.builder.io
Tags
Annotators
URL
-
-
www.youtube.com www.youtube.com
-
-
www.skcript.com www.skcript.com
Tags
Annotators
URL
-
-
javascript.plainenglish.io javascript.plainenglish.io
-
legendapp.com legendapp.com
Tags
Annotators
URL
-
-
legendapp.com legendapp.com
Tags
Annotators
URL
-
-
twitter.com twitter.com
Tags
Annotators
URL
-
-
blog.axlight.com blog.axlight.com
-
codedamn.com codedamn.com
Tags
Annotators
URL
-
-
letsbuildui.dev letsbuildui.dev
- Jun 2023
-
betterprogramming.pub betterprogramming.pub
-
marmelab.com marmelab.com
-
stackoverflow.com stackoverflow.com
-
reactagent.io reactagent.io
-
- May 2023
-
www.reddit.com www.reddit.com
-
github.com github.com
-
js /** * This component is just a Box with border. * It serves as an example of how you can incorporate * components together. * * Component also has slots, methods and events. * * @component * @example <caption>Basic usage just with the default slot</caption> * <Box> * I am inside a slot * </Box> * * @example <caption>Using second component inside</caption> * <Box> * <ProgressBar :spent="spent" :remaining="50"></ProgressBar> * </Box> * * @example <caption>Example of passing an entire component in a preview</caption> * { * template: `<Box> * <ProgressBar :spent="spent" :remaining="50"></ProgressBar> * <ProgressBar :spent="50" :remaining="50" style="margin-top: 20px"></ProgressBar> * </Box>`, * data: function() { * return {spent: 223}; * } * } */ export default { name: "Box", props: { /** * This will be in the header */ title: { type: String, default: "My box" } }, methods: { /** * Also, you can describe methods for each component * the same as you would do this in regular @jsdoc * documented file * * @param {string} prop1 some example property * @param {string} prop2 other property */ exampleMethod(prop1, prop2) { // method body // The method could even throw an event /** * This event could be thrown by component in case * of some kind of unexpected behaviour. * * @category API * @event unexpectedEvent */ this.$emit('unexpecteEvent') } } }
Tags
Annotators
URL
-
-
lightrains.com lightrains.com
Tags
Annotators
URL
-
- Apr 2023
-
blog.somewhatabstract.com blog.somewhatabstract.com
-
vite-remix-router.vercel.app vite-remix-router.vercel.app
Tags
Annotators
URL
-
- Mar 2023
-
www.npmjs.com www.npmjs.com
Tags
Annotators
URL
-
-
jhinter.medium.com jhinter.medium.com
-
codesandbox.io codesandbox.io
-
-
tanstack.com tanstack.com
-
-
twitter.com twitter.com
-
medium.com medium.com
-
sebastienlorber.com sebastienlorber.com
-
The Records & Tuples proposal will enforce immutability, and prevent common state mutation mistakes:
```js const Hello = ({ profile }) => { // prop mutation: throws TypeError profile.name = 'Sebastien updated';
return
Hello {profile.name}
; };function App() { const [profile, setProfile] = React.useState(#{ name: 'Sebastien', });
// state mutation: throws TypeError profile.name = 'Sebastien updated';
return <Hello profile={profile} />; } ```
-
-
rolandjitsu.github.io rolandjitsu.github.io
-
patterns.dev patterns.dev
Tags
Annotators
URL
-
-
www.plasmic.app www.plasmic.app
Tags
Annotators
URL
-
-
beta.nextjs.org beta.nextjs.org
-
Streaming allows you to break down the page's HTML into smaller chunks and progressively send those chunks from the server to the client.
-
-
www.telerik.com www.telerik.com
Tags
Annotators
URL
-
-
www.telerik.com www.telerik.com
-
-
Suspense itself will show fallbacks when not ready and reveal the contents when promises resolve, problem is that if there are multiple Suspense components, it could lead to flickering because of the order is not assured, that’s why we need sorta coordinating. SuspenseList is exactly for this.
```html
<div>Hi</div><React.SuspenseList revealOrder="forwards"> <React.Suspense fallback={\<p>loading...\
}> <Child resource={resource1} /> </React.Suspense> <React.Suspense fallback={\<p>loading...\}> <Child resource={resource2} /> </React.Suspense> <React.Suspense fallback={\<p>loading...\}> <Child resource={resource3} /> </React.Suspense> </React.SuspenseList> ```We can see that the revealing order is kept, from top to bottom, even though the 2nd promise if fulfilled sooner.
-
-
-
Fortunately with webpackChunkName in an inline comment, we can instruct webpack to name the file something much friendlier.
js const HeavyComponent = lazy(() => import(/* webpackChunkName: "HeavyComponent" */ './HeavyComponent');
-
-
plainenglish.io plainenglish.io
-
Similar to prefetching, you can specify the chunk name with an inline comment using the webpackChunkName key
js const LazyLoad = lazy(() => import(/* webpackChunkName: 'lazyload' */ './LazyLoad') );
-
For example, if the user is on the login page, you can load the post-login home page. An inline comment with the webpackPrefetch key within the dynamic import function will instruct Webpack to do just this.
```js const PrefetchLoad = lazy(() => import( / webpackPrefetch: true / './PrefetchLoad' ) );
const App = () => { return ( <Suspense fallback="Loading"> {condition && <PrefetchLoad />} </Suspense> ); }; ```
-
Now when App is rendered and a request is initiated to get the LazyLoad code, the fallback Loading is rendered. When this request completes, React will then render LazyLoad.
js const App = () => { return ( <Suspense fallback="Loading"> <LazyLoad /> </Suspense> ); };
-
Now, App and LazyLoad are in separate code chunks. A request is sent to fetch the LazyLoad code chunk only when App is rendered. When the request completes, React will then renderLazyLoad. You can verify this by looking at the Javascript requests in the network inspector.
```js import React, { lazy } from 'react';
const LazyLoad = lazy(() => import('./LazyLoad'));
const App = () => { return <LazyLoad />; }; ```
-
-
Tags
Annotators
URL
-
-
linguinecode.com linguinecode.com
-
You can have multiple nested React.lazy components inside React.Suspense.
```js
const CatAvatar = React.lazy(() => import('./path/to/cat/avatar')); const ThorAvatar = React.lazy(() => import('./path/to/cat/thor-avatar'));
const AppContainer = () => ( <React.Suspense fallback="loading..."> <CatAvatar /> <ThorAvatar /> </React.Suspense> ); ```
-
-
stackoverflow.com stackoverflow.com
-
www.npmjs.com www.npmjs.com
Tags
Annotators
URL
-
-
www.npmjs.com www.npmjs.com
Tags
Annotators
URL
-
-
emnudge.dev emnudge.dev
-
-
blog.bitsrc.io blog.bitsrc.io
-
```js // FromStream component
import { PureComponent } from 'react';
export default class FromStream extends PureComponent { constructor(props) { super(props); this.state = { value: false }; }
componentDidMount() { this.initStream(); }
componentDidUpdate(prevProps) { if (prevProps.stream !== this.props.stream) { this.initStream(); } }
componentWillUnmount() { if (this.unSubscribe) { this.unSubscribe(); } }
initStream() { if (this.unSubscribe) { this.unSubscribe(); this.unSubscribe = null; }
if (this.props.stream) { const onValue = (value) => { this.setState(() => ({ value: map(value) })); }; this.props.stream.onValue(onValue); this.unSubscribe = () => stream.offValue(onValue); }
}
render() { return this.props.children(this.state && this.state.value); } } ```
```js // Date/Time import React from 'react'; import Kefir from 'kefir'; import FromStream from './FromStream';
const dateStream = Kefir.interval(1000).map(() => new Date().toString());
export default () => ( <FromStream stream={dateStream}> {(dateString) => dateString} </FromStream> ); ```
```js // Scroll import React from 'react'; import Kefir from 'kefir'; import FromStream from './FromStream';
const scrolledPercentStream = Kefir.fromEvents(document, 'scroll').map((e) => { const scrollY = window.document.pageYOffset; const scrollHeight = e.target.body.scrollHeight; return scrollY / (scrollHeight - windiw.innerHeight) * 100; });
export default () => ( <FromStream stream={scrolledPercentStream}> {(percent) => ( <div className="bar" style={{ top: <code>${percent}% }}></div> )} </FromStream> ); ```
-
-
marconijr.com marconijr.com
-
```js import { useState, useEffect } from 'react';
interface StreamState { data: Uint8Array | null; error: Error | null; controller: AbortController; }
const useAbortableStreamFetch = (url: string, options?: RequestInit): { data: Uint8Array | null, error: Error | null, abort: () => void, } => {
const [state, setState] = useState<StreamState>({ data: null, error: null, controller: new AbortController(), });
useEffect(() => { (async () => { try { const resp = await fetch(url, { ...options, signal: state.controller.signal, }); if (!resp.ok || !resp.body) { throw resp.statusText; }
const reader = resp.body.getReader(); while (true) { const { value, done } = await reader.read(); if (done) { break; } setState(prevState => ({ ...prevState, ...{ data: value } })); } } catch (err) { if (err.name !== 'AbortError') { setState(prevState => ({ ...prevState, ...{ error: err } })); } } })(); return () => state.controller.abort();
}, [url, options]);
return { data: state.data, error: state.error, abort: () => state.controller && state.controller.abort(), }; };
export default useAbortableStreamFetch; ```
-
-
-
-
tkdodo.eu tkdodo.eu
Tags
Annotators
URL
-
-
-
```js import React, { Component } from 'react'; import './style.css'; import ndjsonStream from 'can-ndjson-stream';
class App extends Component { constructor(props) { super(props);
this.state = { todos: [] };
}
componentDidMount(){ fetch('http://localhost:5000/api/10', { method: 'get' }).then(data => { return ndjsonStream(data.body); }).then((todoStream) => { const streamReader = todoStream.getReader(); const read = result => { if (result.done) return;
this.setState({ todos: this.state.todos.concat([result.value.user]) }); streamReader.read().then(read); }; streamReader.read().then(read); }).catch(err => { console.error(err) });
}
render() { return ( <div className="App">
React + NDJSON Stream Demo
-
{this.state.todos.map((todo, i) =>
- {todo} )}
export default App; ```
-
-
-
Pitfall #1: Server-Side Rendering Attacker-Controlled Initial State
```html
<script>window.__STATE__ = ${JSON.stringify({ data })}</script>```
-
Pitfall #3: Misunderstanding What it Means to Dangerously Set
-
Pitfall #2: Sneaky Links
-
-
-
thomasnguyen.site thomasnguyen.site
-
One option is to use the serialize-javascript NPM module to escape the rendered JSON.
html { username: "pwned", bio: "</script><script>alert('XSS Vulnerability!')</script>" }
-
This is risky because JSON.stringify() will blindly turn any data you give it into a string (so long as it is valid JSON) which will be rendered in the page. If { data } has fields that un-trusted users can edit like usernames or bios, they can inject something like this:
json { username: "pwned", bio: "</script><script>alert('XSS Vulnerability!')</script>" }
-
Sometimes when we render initial state, we dangerously generate a document variable from a JSON string. Vulnerable code looks like this:
```html
<script>window.__STATE__ = ${JSON.stringify({ data })}</script>```
-
Server-side rendering attacker-controlled initial state
-
-
yezyilomo.github.io yezyilomo.github.io
Tags
Annotators
URL
-
-
www.freecodecamp.org www.freecodecamp.org
-
To pass along the state, the template attaches state to window.__STATE__ inside a <script> tag.Now you can read state on the client side by accessing window.__STATE__.
-
-
www.youtube.com www.youtube.com
-
-
www.youtube.com www.youtube.com
Tags
Annotators
URL
-
-
tanstack.com tanstack.com
-
ogzhanolguncu.com ogzhanolguncu.com
Tags
Annotators
URL
-
-
codesandbox.io codesandbox.io
Tags
Annotators
URL
-
-
gatewayapps.github.io gatewayapps.github.io
-
www.npmjs.com www.npmjs.com
-
kyleshevlin.com kyleshevlin.com
-
- Feb 2023
-
betterprogramming.pub betterprogramming.pub
-
www.youtube.com www.youtube.com
-
-
www.aboutmonica.com www.aboutmonica.com
-
patterns.dev patterns.dev
Tags
Annotators
URL
-
-
patterns.dev patterns.dev
Tags
Annotators
URL
-
-
patterns.dev patterns.dev
Tags
Annotators
URL
-
-
patterns.dev patterns.dev
-
-
beta.reactjs.org beta.reactjs.org
-
github.com github.com
-
```js import type { EntryContext } from "@remix-run/cloudflare"; import { RemixServer } from "@remix-run/react"; import isbot from "isbot"; import { renderToReadableStream } from "react-dom/server";
const ABORT_DELAY = 5000;
const handleRequest = async ( request: Request, responseStatusCode: number, responseHeaders: Headers, remixContext: EntryContext ) => { let didError = false;
const stream = await renderToReadableStream( <RemixServer context={remixContext} url={request.url} abortDelay={ABORT_DELAY} />, { onError: (error: unknown) => { didError = true; console.error(error);
// You can also log crash/error report }, signal: AbortSignal.timeout(ABORT_DELAY), }
);
if (isbot(request.headers.get("user-agent"))) { await stream.allReady; }
responseHeaders.set("Content-Type", "text/html"); return new Response(stream, { headers: responseHeaders, status: didError ? 500 : responseStatusCode, }); };
export default handleRequest; ```
-
-
mxstbr.com mxstbr.com
Tags
Annotators
URL
-
-
www.joshwcomeau.com www.joshwcomeau.com
Tags
Annotators
URL
-
-
marcoghiani.com marcoghiani.com
-
-
Node.js
js import { renderToPipeableStream } from "react-dom/server.node"; import React from "react"; import http from "http"; const App = () => ( <html> <body> <h1>Hello World</h1> <p>This is an example.</p> </body> </html> ); var didError = false; http .createServer(function (req, res) { const stream = renderToPipeableStream(<App />, { onShellReady() { res.statusCode = didError ? 500 : 200; res.setHeader("Content-type", "text/html"); res.setHeader("Cache-Control", "no-transform"); stream.pipe(res); }, onShellError(error) { res.statusCode = 500; res.send( '<!doctype html><p>Loading...</p><script src="clientrender.js"></script>', ); }, onAllReady() { }, onError(err) { didError = true; console.error(err); }, }); }) .listen(3000);
Deno
```js import { renderToReadableStream } from "https://esm.run/react-dom/server"; import * as React from "https://esm.run/react";
const App = () => ( <html> <body>
Hello World
This is an example.
</body> </html> );const headers = { headers: { "Content-Type": "text/html", "Cache-Control": "no-transform", }, };
Deno.serve( async (req) => { return new Response(await renderToReadableStream(<App />), headers); }, { port: 3000 }, ); ```
Bun
```js import { renderToReadableStream } from "react-dom/server"; const headers = { headers: { "Content-Type": "text/html", }, };
const App = () => ( <html> <body>
Hello World
This is an example.
</body> </html> );Bun.serve({ port: 3000, async fetch(req) { return new Response(await renderToReadableStream(<App />), headers); }, }); ```
-
-
beta.reactjs.org beta.reactjs.org
-
beta.reactjs.org beta.reactjs.org
-
www.youtube.com www.youtube.com
-
-
blog.logrocket.com blog.logrocket.com
-
prateeksurana.me prateeksurana.me
-
tom-sherman.com tom-sherman.com
-
reactjs.org reactjs.org
Tags
Annotators
URL
-
-
beta.reactjs.org beta.reactjs.org
Tags
Annotators
URL
-
-
suspense.vercel.app suspense.vercel.app
-
suspense.vercel.app suspense.vercel.app
Tags
Annotators
URL
-
-
suspense-npm.vercel.app suspense-npm.vercel.app
-
suspense-npm.vercel.app suspense-npm.vercel.app
Tags
Annotators
URL
-
-
dillonshook.com dillonshook.com
Tags
Annotators
URL
-
-
www.reddit.com www.reddit.com
-
news.ycombinator.com news.ycombinator.com
-
-
beta.reactjs.org beta.reactjs.org
-
legacy.reactjs.org legacy.reactjs.org
-
ogzhanolguncu.com ogzhanolguncu.com
Tags
Annotators
URL
-
-
preactjs.com preactjs.com
-
preactjs.com preactjs.com
Tags
Annotators
URL
-
-
twitter.com twitter.com
-
www.builder.io www.builder.io
-
twitter.com twitter.com
Tags
Annotators
URL
-
-
qwik.builder.io qwik.builder.io
-
-
-
-
punits.dev punits.dev
-
remix.run remix.run
Tags
Annotators
URL
-
-
egghead.io egghead.io
Tags
Annotators
URL
-
-
svelte.dev svelte.devSvelte1
-
-
react-typescript-cheatsheet.netlify.app react-typescript-cheatsheet.netlify.app
Tags
Annotators
URL
-
-
www.typescriptlang.org www.typescriptlang.org
Tags
Annotators
URL
-
- Jan 2023
- Dec 2022
-
stackoverflow.com stackoverflow.com
-
stackoverflow.com stackoverflow.com
-
I had been wrapping my components with an improper tag that is, NextJS is not comfortable having a p tag wrapping your divs, sections etc so it will yell "Hydration failed because the initial UI does not match what was rendered on the server". So I solved this problem by examining how my elements were wrapping each other.
-
-
blog.nparashuram.com blog.nparashuram.com
-
TL;DR; A custom renderer for ReactJS that uses Web Workers to run the expensive Virtual DOM diffing calculations
-
-
blog.nparashuram.com blog.nparashuram.com
-
Tl;Dr; ReactJS is faster when Virtual DOM reconciliations are done on a Web Worker thread.
-
-
dexie.org dexie.org
-
```js import React from "react"; import Dexie from "dexie"; import { useLiveQuery } from "dexie-react-hooks"; import { db } from "./db";
// // React component // export function OldFriendsList() { const friends = useLiveQuery( () => db.friends .where('age') .above(75) .toArray() );
if (!friends) return null; // Still loading.
return
-
{ friends.map(friend =>
- {friend.name}, {friend.age} ) }
-
-
Tags
Annotators
URL
-
-
www.developerway.com www.developerway.com
-
Context selectors, however, could be faked with the use of higher-order components and React.memo.
-
There is no way to prevent a component that uses a portion of Context value from re-rendering, even if the used piece of data hasn’t changed, even with useMemo hook.
-
✅ Preventing Context re-renders: Context selectors
-
If Context manages a few independent data chunks, they can be split into smaller providers under the same provider. That way, only consumers of changed chunk will re-render.
-
✅ Preventing Context re-renders: splitting data into chunks
-
That way, components that use API only won’t re-render when the data changes.
-
If in Context there is a combination of data and API (getters and setters) they can be split into different Providers under the same component. That way, components that use API only won’t re-render when the data changes.
-
✅ Preventing Context re-renders: splitting data and API
-
If Context Provider is placed not at the very root of the app, and there is a possibility it can re-render itself because of changes in its ancestors, its value should be memoized.
-
✅ Preventing Context re-renders: memoizing Provider value
-
Preventing re-renders caused by Context
-
⛔️ Antipattern: random value as key in lists
-
if the list is static, i.e. elements are not added/removed/inserted/re-ordered
-
It is okay to use array’s index as key, if the list is static, i.e. elements are not added/removed/inserted/re-ordered.
-
Value in key should be a string, that is consistent between re-renders for every element in the list.
-
Important: just providing key attribute will not improve lists' performance. To prevent re-renders of list elements you need to wrap them in React.memo and follow all of its best practices.
-
Improving re-render performance of lists
-
the typical use case for useMemo would be to memoize React elements. Usually parts of an existing render tree or results of generated render tree, like a map function that returns new elements
-