DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Sebastien Lorber
Sebastien Lorber

Posted on

React 18 milestone: React-Redux adopts useSyncExternalStore

This is a sample from my This Week In React newsletter. Subscribe for more!

This Week In React newsletter banner


React-Redux v8 alpha.0 was just announced by Mark Erikson.

The library is now fully rewritten in TypeScript.

More importantly, React-Redux v8 is adopting a new React 18 hook useSyncExternalStore (replacing useMutableSource).

This hook allows React to work properly in concurrent mode and sync with an external state (from Redux) without tearing (the UI can't become inconsistent with store state).

This hook is the "level 2" (make it right) of the state subscription ladder:

image.png

Dan Abramov explains it's an important milestone for React 18:

For the first time we’ve been able to move the β€œmeat” of the react-redux bindings implementation into react itself.
It wasn’t a lot of code, but it relied on a bunch of hacks and complexity that kept growing. Now that β€œmeat” is 5 lines of code, we handle the rest.

import { useSyncExternalStoreExtra } from 'use-sync-external-store/extra';

// React-Redux v8 alpha code in useSelector()
const selectedState = useSyncExternalStoreExtra(
  store.subscribe, 
  store.getState, 
  // TODO Need a server-side snapshot here
  store.getState, 
  selector, 
  equalityFn
);
Enter fullscreen mode Exit fullscreen mode

To ease incremental adoption in libraries today, an external package use-sync-external-store has been published, allowing to use this hook with a consistent API on React 16, 17 & 18.

Unlike the former useMutableSource API, this new hook supports unstable, inline selectors without re-subscribing, and you won't need to wrap selectors in useCallback to stabilize them:

// Not ideal
const user = useSelector(
  useCallback(state => state.user,[])
);

// Simpler
const user = useSelector(state => state.user)
Enter fullscreen mode Exit fullscreen mode

The community remains very interested to have a native useContextSelector() hook in React core.

A performant useContextSelector() hook would allow Redux to try again passing the store state directly as context value, instead of passing a store object and managing subscriptions internally. React would now hold entirely the Redux state and the React-Redux bindings would move to the ladder's stage 3 (make it fast). This stage would permit React to avoid unnecessary rendering work when a Redux store update happens while a concurrent rendering is in progress.

useContextSelector is still under research and is not a mandatory feature for React 18 to land. Andrew Clark commented that it will more likely be released in a minor 18.x release.

Top comments (3)

Collapse
jzombie profile image
jzombie

I'd like to contact you in regards to some questions about potentially sponsoring one of your newsletters, and finding it difficult to contact you directly, to ask some questions.

If interested, please connect w/ me on LinkedIn linkedin.com/in/jeremyharrisconsul... (which I could miss your message there as it is swamped), or even better, shoot me an email at info @ zenosmosis.com.

Collapse
sebastienlorber profile image
Sebastien Lorber Author

Hey
I'm pretty easy to contact on LinkedIn or Twitter, just send a message ^^
My English newsletterr is not "yet" launched and I think it's way too small to accept sponsorships, and not worth it.
My French one accept sponsors: sebastienlorber.com/sponsor

Collapse
jzombie profile image
jzombie

Thanks for the response. Just sent you a message on LinkedIn.

πŸ‘€ Every week new members join DEV and share a bit about them in our Welcome Thread

Welcome them to DEV and share a bit about yourself.