Skip to content

Instantly share code, notes, and snippets.

@Jarred-Sumner
Last active February 24, 2024 18:02
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Jarred-Sumner/1f13f48c12e84a7d9a05365018834475 to your computer and use it in GitHub Desktop.
Save Jarred-Sumner/1f13f48c12e84a7d9a05365018834475 to your computer and use it in GitHub Desktop.
I think this is how React Fast Refresh works, but I'm not 100% sure

How React Fast Refresh works

Implementations:

Additional reading:

From reading and Dan Abramov's comment, there are really five parts.

  1. At the top of the file:
    1. Declare a $RefreshReg$ if it doesn't exist
      • This really just does:
        RefreshRuntime.register(ComponentIdentifier, ComponentIdentifier.name);
    2. Run var _s${componentIndex} = $RefreshSig$() to generate a function for updating react refresh scoped to the component. So it's one per component.
      • This really just does:
        RefreshRuntime.createSignatureFunctionForTransform();
  2. Register all React components[2] defined in the module scope by calling the equivalent of $RefreshReg$(ComponentIdentifier, "ComponentName")
  3. For each registered component:
    1. Call _s() to mark the first render of this component for "react-refresh/runtime". Call this at the start of the React component's function body
    2. Track every call expression to a hook[3] inside the component, including:
      • Identifier of the hook function
      • Arguments passed
    3. For each hook's call expression, generate a signature key which is
      • The hook's identifier ref

      • The S.Decl (VariableDeclarator)'s source

            var [foo, bar] = useFooBar();
             // ^--------^ This region, I think. [Judging from this line](https://github.com/facebook/react/blob/master/packages/react-refresh/src/ReactFreshBabelPlugin.js#L407)
      • For the useState hook, also hash the source of the first argument if it exists e.g. useState(foo => true);

      • For the useReducer hook, also hash the source of the second argument if it exists e.g. useReducer({}, () => ({}));

    4. If the hook component is not builtin and is defined inside a component, always reset the component state
  4. From the signature key generated in 3., call one of the following:
    • _s(ComponentIdentifier, hash(signature));
    • _s(ComponentIdentifier, hash(signature), true /* forceReset */);
    • _s(ComponentIdentifier, hash(signature), false /* forceReset */, () => [customHook1, customHook2, customHook3]); Note: This step is only strictly required on rebuild.
  5. if (isReactComponentBoundary(exports)) enqueueUpdateAndHandleErrors();

FAQ

  1. Q: From a parser's perspective, what's a component?

    A: typeof name === 'string' && name[0] >= 'A' && name[0] <= 'Z' -- source

  2. Q: From a parser's perspective, what's a hook?

    A: /^use[A-Z]/ -- source

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment