FG
💻 Software🌐 Web & Full-Stack

Bug: MobX-like observer pattern doesn't work with Fast Refresh because Hooks don't get detected

Fresh5 days ago
Mar 14, 20260 views
Confidence Score60%
60%

Problem

React version: 17.0.0 Steps To Reproduce 1. https://codesandbox.io/s/react-refresh-webpack-plugin-rendered-more-hooks-than-during-the-previous-render-issue-ezcrz?file=/src/Comp.js 2. Delete one of the hooks there Link to code example: https://codesandbox.io/s/react-refresh-webpack-plugin-rendered-more-hooks-than-during-the-previous-render-issue-ezcrz?file=/src/Comp.js The current behavior You get "Rendered more hooks than during the previous render" error The expected behavior Should hot reload and re-mount the component. The source of the issue have two parts: 1. react-refresh and the bundler fails to inject signature to the component 2. When no signature apparent, `react-refresh` consider the components as compatible, which is not always true, as in the repro https://github.com/facebook/react/blob/9aca239f11f31109dc1a229aa1571c2bf02f5524/packages/react-refresh/src/ReactFreshRuntime.js#L126-L132 I've filed an issue also for the webpack plugin: https://github.com/pmmmwh/react-refresh-webpack-plugin/issues/266 Mobx related issue: https://github.com/mobxjs/mobx/issues/2668

Error Output

error


## The expected behavior

Unverified for your environment

Select your OS to check compatibility.

1 Fix

Canonical Fix
Unverified Fix
New Fix – Awaiting Verification

Fix MobX Observer Pattern Compatibility with Fast Refresh

Medium Risk

The issue arises because the react-refresh plugin fails to correctly inject the component signature when using MobX with hooks. This results in the component being treated as compatible even when the number of hooks rendered changes, leading to the 'Rendered more hooks than during the previous render' error. This is compounded by the way MobX manages state and reactivity, which can interfere with the expected behavior of React's hooks.

Awaiting Verification

Be the first to verify this fix

  1. 1

    Upgrade React and React Refresh

    Ensure you are using the latest stable versions of React and react-refresh to benefit from the latest bug fixes and improvements.

    bash
    npm install react@latest react-dom@latest @pmmmwh/react-refresh-webpack-plugin@latest
  2. 2

    Modify MobX Observer Usage

    Wrap your MobX component with the observer function to ensure that it properly integrates with React's lifecycle and hooks. This can help in maintaining the expected behavior during hot reloads.

    javascript
    import { observer } from 'mobx-react-lite';
    
    const MyComponent = observer(() => {
      // Your hooks and component logic here
    });
  3. 3

    Add React Refresh Signature

    Manually add a refresh signature to your component to help react-refresh identify it correctly. This can be done by using the `refresh` function provided by the react-refresh library.

    javascript
    import { refresh } from 'react-refresh';
    
    const MyComponent = () => {
      // Your hooks and component logic here
    };
    
    if (module.hot) {
      module.hot.accept('./MyComponent', () => {
        refresh(MyComponent);
      });
  4. 4

    Check for Hook Consistency

    Ensure that the number of hooks called in your component remains consistent across renders. This means avoiding conditional hooks or ensuring that they are always called in the same order.

    javascript
    // Avoid this pattern:
    if (condition) {
      useEffect(() => {});
    }
    // Instead, use:
    useEffect(() => {});
    
  5. 5

    Test Hot Reload Functionality

    After making the above changes, test the hot reload functionality by modifying the component and ensuring that it updates without throwing the hooks error.

    javascript
    Modify a hook or component logic and observe the behavior in the browser.

Validation

Confirm that the application no longer throws the 'Rendered more hooks than during the previous render' error when hot reloading. Additionally, verify that the component updates correctly without requiring a full page reload.

Sign in to verify this fix

Environment

Submitted by

AC

Alex Chen

2450 rep

Tags

reactjavascripttype:-bugcomponent:-fast-refresh