A component suspended while responding to synchronous input
Asked Answered
C

3

52

Error: A component suspended while responding to synchronous input. This will cause the UI to be replaced with a loading indicator. To fix, updates that suspend should be wrapped with startTransition.

I want to retain previous state of Component A when I navigate from Component B to A. In React v17 and React Router v5, I was able to achieved the previous state. But with React v18, I'm getting the above error. Any Idea?

Component A:

const ComponentA = React.lazy(() => import('./ComponentA'));

const App = () => (
  <Suspense fallback={<Loader/>}>
     <Provider store={store}>
       <ComponentA/>
     </Provider>
  </Suspense>
)

Component B:

const ComponentB = React.lazy(() => import('./ComponentB'));

const App = () => (
  <Suspense fallback={<Loader/>}>
    <Provider store={store}>
      <ComponentB/>
    </Provider>
  </Suspense>
)

Node: v16.14.2 React: v18 React Router: v6

Redux v8 not support for React v18 https://github.com/reduxjs/react-redux/issues/1740

Communist answered 9/5, 2022 at 5:57 Comment(0)
C
52

I was also facing a similar issue, adding a parent Suspense fixed it for me. Something like this:

<Suspense fallback={<Loader />}>
  <Component>
    <Suspense fallback={<Loader />}>
      <LazyLoadedComponentA />
    </Suspense>
  </Component>
  <Component>
    <Suspense fallback={<Loader />}>
      <LazyLoadedComponentB />
    </Suspense>
  </Component>
</Suspense>
Crinkly answered 25/5, 2022 at 12:40 Comment(4)
Component A and Component B are deployed in separate container. The above won't work when you are using Router.Communist
Is it valid for react-router?Hofstetter
its not valid for react-router. If we using lazy loading in react-router, we only needs to wrap our Routes with Suspense.Vaseline
This solution works! Can you add explanation on "why" it works or a reference to the source?Grubb
J
2

I found the fix. when you are using nested routes. make sure you are not loading parent component as lazy. there is a chance that child component load faster than parent component. which may cause this issue.

Juan answered 13/5 at 6:9 Comment(0)
A
1

There is another solution which is by using useDeferredValue hook for the input which is causing this issue.

export default function UsersReview() {
    const [userName, setUserName] = useState('');
    const deferredUserName = useDeferredValue(userName);
    return (
      <>
        <label>
          Search for user:
          <input value={userName} onChange={e => setUserName(e.target.value)} />
        </label>
        <Suspense fallback={<LoadingSpinner/>}>
          <UsersResults searchValue={deferredUserName} />
        </Suspense>
      </>
    );
  }

However, in this case you will see the old deferred value insteads of the Suspense fallback until the new results have loaded, and we can show the LoadingSpinner depending on the equality condition between the deferred value and the original value.

  {/* <Suspense fallback={<LoadingSpinner/>}> */}
  {userName !== deferredUserName ? (
    <LoadingSpinner />
  ) : (
    <UsersResults searchValue={deferredUserName} />
  )}
  {/* </Suspense> */}
Alanalana answered 4/5, 2023 at 12:29 Comment(1)
Latest react-router doesnt work on caching previous state. caching state only work on react-router v5Communist

© 2022 - 2024 — McMap. All rights reserved.