Skip to content

Bug: react got runtime error when user breaks the rules of hooks, instead of telling user what to do #28165

Closed
@RexSkz

Description

@RexSkz

React version: 18.2.0

Steps To Reproduce

  1. Open the link below, it will show a page with a button.
  2. Click the button, and you will get the error.

Link to code example: https://codesandbox.io/p/sandbox/a-react-hooks-edge-case-that-causes-react-crash-rddmkh?file=%2Fsrc%2FApp.js%3A1%2C1

The current behavior

Users get a runtime error Cannot read properties of undefined (reading 'length').

image

This is because React uses different data structures in memoizedState, e.g. object for useEffect, array for useCallback. If users break the rules of hooks, the following code will crash, which will confuse users:

function updateCallback(callback, deps) {
  ...
    if (nextDeps !== null) {
      var prevDeps = prevState[1];                  // <- 1. prevState is now an object

      if (areHookInputsEqual(nextDeps, prevDeps)) { // <- 2. passes an undefined here
        return prevState[0];
      }
    }
  }
  ...
}

function areHookInputsEqual(nextDeps, prevDeps) {
  ...
    if (nextDeps.length !== prevDeps.length) {      // <- 3. this will crash - prevDeps is undefined
      error('The final argument passed to %s changed size between renders. The ' + 'order and size of this array must remain constant.\n\n' + 'Previous: %s\n' + 'Incoming: %s', currentHookNameInDev, "[" + prevDeps.join(', ') + "]", "[" + nextDeps.join(', ') + "]");
    }
  }
  ...
}

The expected behavior

Users should receive a React message like other scenarios that break the rules of hooks (Rendered more hooks than during the previous render.).

Actually, if we modify the last hook from useCallback to useEffect, we can get this message.

image

ESLint can not identify this scenario and will not report errors. If it's not the responsibility of React, at least the eslint-plugin-react should detect it.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions