557 Matching Annotations
  1. Sep 2023
    1. ```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})

      ); } ```

  2. Aug 2023
  3. Jul 2023
    1. 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...

  4. Jun 2023
  5. May 2023
    1. 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') } } }

  6. Apr 2023
  7. Mar 2023
    1. 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} />; } ```

    1. Streaming allows you to break down the page's HTML into smaller chunks and progressively send those chunks from the server to the client.

    1. 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.

    1. 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');

    1. 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') );

    2. 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> ); }; ```

    3. 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> ); };

    4. 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 />; }; ```

    1. 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> ); ```

    1. ```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> ); ```

    1. ```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; ```

    1. ```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}
      • )}
      </div> ); } }

      export default App; ```

    1. 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>" }

    2. 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>" }

    3. 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>

      ```

    4. Server-side rendering attacker-controlled initial state
    1. 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__.
  8. Feb 2023
    1. ```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; ```

    1. 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); }, }); ```

  9. Jan 2023
  10. Dec 2022
    1. 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.
    1. ```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}
      • ) }
      ; } ```

    1. Context selectors, however, could be faked with the use of higher-order components and React.memo.
    2. 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.
    3. ✅ Preventing Context re-renders: Context selectors

    4. 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.
    5. ✅ Preventing Context re-renders: splitting data into chunks

    6. That way, components that use API only won’t re-render when the data changes.
    7. 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.
    8. ✅ Preventing Context re-renders: splitting data and API

    9. 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.
    10. ✅ Preventing Context re-renders: memoizing Provider value

    11. Preventing re-renders caused by Context
    12. ⛔️ Antipattern: random value as key in lists

    13. if the list is static, i.e. elements are not added/removed/inserted/re-ordered
    14. 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.
    15. Value in key should be a string, that is consistent between re-renders for every element in the list.
    16. 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.
    17. Improving re-render performance of lists

    18. 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
    19. useMemo has its cost (consumes a bit of memory and makes initial render slightly slower)