Skip to content

Bug: re-ordering components with stable keys invalidates refs/state, since 19.0.0 #34307

@rain-sk

Description

@rain-sk

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

  1. git clone https://github.com/rain-sk/synth.kitchen.git && cd synth.kitchen
  2. git checkout demo-react19-issues
  3. cd app/web
  4. npm i && npm run dev
  5. Visit localhost:8080 and press "start"
  6. 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
  7. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Status: UnconfirmedA potential issue that we haven't yet confirmed as a bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions