2

In following code, Sample uses a async function to get some data. I will be using that data to update the Redux store so any component can access the username within the application.

const resource = fetchData();

function Sample() {
    // throws a promise when retrieving data
    const name = resource.read();

    const dispatch = useDispatch();
    dispatch(setUsername(name));

    const username = useSelector((state) => state.username);

    return <div>User: {username}</div>;
}

<Suspense fallback="loading....">
    <Sample />
</Suspense>

Here, lets assume there is no way my application can proceed without the username. Well, <Suspense> at parent level achieves that up until data are fetched from the resource. However, there is a slight gap from Redux event dispatch to <Sample> component re-render where is displays User: instead of loading.... (event don't force the re-render immediately so username is empty). So I will see following content in the web page in the same order

loading.... --> User: --> User: Srinesh

So my requirement is to show loading.... until store is updated. On the web page, I'm expecting to see,

loading.... --> User: Srinesh

Is there a way to achieve this without using another condition at <Sample> component level to show loading.... if the username is null?

s1n7ax
  • 2,750
  • 6
  • 24
  • 53

1 Answers1

2

The first issue is that dispatching in the middle of component rendering logic is a side effect, and you must never do that.

A safer place to put that would be in a useLayoutEffect hook, which will dispatch as soon as the component is done rendering, but force a synchronous re-render before the browser has a chance to paint. That way you won't see the flash.

markerikson
  • 63,178
  • 10
  • 141
  • 157