Skip to content

Performance: remove memory allocations in useReducer #33165

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

romgrk
Copy link
Contributor

@romgrk romgrk commented May 9, 2025

Summary

Take 2 for #27383. I'm once again investigating a high-performance situation, and having a state hook that doesn't needlessly allocate memory on every render would be invaluable.

This time, I've added an Object.freeze() in dev mode to ensure nothing unholy is happening to the memoizedState.

How did you test this change?

yarn test and local build of React.

@react-sizebot
Copy link

Comparing: 3820740...9c3343e

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable/react-dom/cjs/react-dom.production.js = 6.68 kB 6.68 kB = 1.83 kB 1.83 kB
oss-stable/react-dom/cjs/react-dom-client.production.js = 528.09 kB 528.09 kB = 93.17 kB 93.17 kB
oss-experimental/react-dom/cjs/react-dom.production.js = 6.69 kB 6.69 kB = 1.83 kB 1.83 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js = 646.40 kB 646.40 kB = 113.71 kB 113.71 kB
facebook-www/ReactDOM-prod.classic.js = 674.15 kB 674.15 kB = 118.41 kB 118.41 kB
facebook-www/ReactDOM-prod.modern.js = 664.43 kB 664.43 kB = 116.81 kB 116.81 kB

Significant size changes

Includes any change greater than 0.2%:

(No significant changes)

Generated by 🚫 dangerJS against 9c3343e

workInProgressHook.memoizedState = newState;

return [newState, dispatch];
workInProgressHook.memoizedState = [newState, dispatch];
Copy link
Contributor Author

@romgrk romgrk May 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about .memoizedState[0] = newState, but that would make the return value of useState stable across renders, even when there are changes, and that would be conceptually wrong for this API.


Tbh my true aim was to have a state hook with a stable value (and absolutely no memory allocations beyond initialization), but it would have an API like this:

const enabled = useStableState(false);
// => { get: () => boolean, set: (v: boolean) => void }

return (
  <button onClick=(() => enabled.set(!enabled.get())>
    {enabled.get() ? 'enabled' : 'disabled'}
  </button>
)

However, I fear it won't be possible without adding it directly in React as I need access to the internals to implement it properly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants