Changes to Suspense effects semantics · reactwg/react-18 · Discussion #31 (original) (raw)

Last week I posted about a new "strict effects" mode and how it would impact effects for development builds. React 18 will also include a small change to how layout effects work with Suspense. This thread explains that change and how you can prepare for it.

What's changing?

If a component mounts within a Suspense boundary and is later hidden (because of something else suspending), React will cleanup that component’s layout effects by calling useLayoutEffect cleanup functions or componentWillUnmount. After the suspended boundary resolves, React will recreate the component’s layout effects again by calling useLayoutEffect or componentDidMount.

This change is being made to avoid bugs that may occur from things like reading layout in a hidden tree.

Will this impact a lot of my code?

The scenario described above is not common and can be avoided entirely by using the new useTransition API to ensure that Suspense does not revert to its fallback state after being mounted.

For example, here is a state update that might cause the ProfilePage component to re-suspend afer mounting:

function Example() { const [resource, setResource] = useState(initialResource); return ( <> <button onClick={() => { const nextUserId = getNextId(resource.userId); setResource(fetchProfileData(nextUserId)); }} > Next <Suspense fallback={}> </> ); }

Wrap the state update in a "transition" to prevent the ProfilePage from being unmounted while suspending. This lets React know that it should wait for the update to complete:

function Example() { const [resource, setResource] = useState(initialResource); const [startTransition, isPending] = useTransition(SUSPENSE_CONFIG); return ( <> <button disabled={isPending} onClick={() => { startTransition(() => { const nextUserId = getNextId(resource.userId); setResource(fetchProfileData(nextUserId)); }); }} > Next <Suspense fallback={}> </> ); }

As a bonus, React also returns an isPending value which can be used for things like disabling the button while the previous transition is still in progress.

We expect that most effects should "just work" with this change because of strict effects mode. Refer to this post for examples of the types of effects that may require changes.

For more information on strict effects, see: