-
Notifications
You must be signed in to change notification settings - Fork 49.3k
Description
I've tested with 18.3.1, 19.0.0, and 19.1.1.
I build a modular synth application which uses the Web Audio API. Since it's possible for synth patches to grow quite large, I memoize the ordered list of modules for the sake of having a sensible keyboard navigation order. This means that the order of rendered modules can change.
Up until React 18.3.1, this changing order of rendered modules was not causing any issues. I make sure to use stable unique identifiers as keys when rendering, so components' internal state remains stable as the modules are dragged around the canvas.
Here's a snippet of the code used to render the modules:
const sortedModules = useMemo(
() => {
// ... order the modules based on their positions in the canvas
}),
[state.modulePositions, state.modules],
);
return (
<>
{sortedModules.map(([module, position]) => (
<Module
key={module.moduleKey}
module={module}
position={position}
state={state}
dispatch={dispatch}
/>
))}
</>
);
Internally, <Module />
calls a hook which stores a ref to a "node" object – which acts as its handle into the audio API – and initializes it like so:
// ...
const nodeRef = useRef<NodeType>(undefined);
if (!nodeRef.current) {
nodeRef.current = nodeFactory();
}
// ...
So, since React 19.0.0, this ref seems to get out of sync when the order of the rendered components changes.
React version: 19.0.0, 19.1.1
Steps To Reproduce
git clone https://github.com/rain-sk/synth.kitchen.git && cd synth.kitchen
git checkout demo-react19-issues
cd app/web
npm i && npm run dev
- Visit localhost:8080 and press "start"
- Double-click in the center of the screen, then choose one of the options in the menu to add a new module to the canvas
- Drag the output module to the bottom-right corner of the screen, past the newly-added module
Expected:
- internal module state is stable regardless of render order
Result:
- hit the debugger line in the
useNode
hook, indicating that the ref was reset, even though we've already initialized the corresponding node
Note: the commit behind the HEAD of demo-react19-issues
is the one which adds the debugger statement. Switching to that commit (b8f76f9f845328a6e83fdd3a13981f82cf16fe11
) and re-installing node_modules, demonstrates that this problem did not exist prior to React 19.
Link to code example:
The current behavior
Changing render order of components with stable keys results in broken internal refs.
The expected behavior
Internal refs of react components are stable regardless of render order, given stable key props.