Description
React version: 18.2.0
Steps To Reproduce
- Open the link below, it will show a page with a button.
- 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')
.

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.

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.