DEV Community

Cover image for React - Don't update parent state in the rendering phase of the child
Jacopo Marrone @tresorama
Jacopo Marrone @tresorama

Posted on

3 2

React - Don't update parent state in the rendering phase of the child

TLDR;
Don't update parent state in the rendering phase of the child component


Long story

Visualize in your mind this Abstract React tree:

<WebSite>

  <LoadingSpinner />

  <PageContent>
    <A>
      <ASub>
        <ASubSub>
          <LoadingTriggerA />
        </ASubSub>
      </ASub>
    </A>
    <B>
      <BSub>
        <BSubSub>
          <LoadingTriggerB />
        </BSubSub>
      </BSub>
    </B>
  </PageContent>

</WebSite>

Enter fullscreen mode Exit fullscreen mode

The goal is to render a single LoadingSpinner in our whole website, and being able to trigger the LoadingSpinner visibility from LoadingTriggerA and LoadingTriggerB when they need to.

How to solve this without passing functions down the tree - aka โ€œprop drillingโ€œ ?

React Context, using a "useAppLoading" custom hook.

This custom hook takes care of maintaining the visibility state of the Loading component, and to render it.
This hook exposes us a show and a hide function.

In this post we are focused not on the custom hook, but here you can find the code for build a "useAppLoading" custom hook.

import { AppLoadingProvider, useAppLoading } from './my-custom-hook/useAppLoading';

const Website  = () => {
  return (
    <AppLoadingProvider>
      <PageContent  /> // LoadingTriggerA and LoadingTriggerB are descendants of this
    </AppLoadingProvider>
    );
};

const LoadingTriggerA = () => {
   const {showLoading, hideLoading} = useAppLoading();
   ...
   return <div>....</div>;
}

const LoadingTriggerB = () => {
   const {showLoading, hideLoading} = useAppLoading();
   ...
   return <div>....</div>;
}
Enter fullscreen mode Exit fullscreen mode

It seams ok.
But how do we call "show()" and "hide()" functions ???
This is THE POINT of this post.

Maybe like this ??

const LoadingTriggerA = () => {
   const {showLoading, hideLoading} = useAppLoading();
   showLoading();
   return <div>....</div>;
}

const LoadingTriggerB = () => {
   const {showLoading, hideLoading} = useAppLoading();
   hideLoading();
   return <div>....</div>;
}
Enter fullscreen mode Exit fullscreen mode

Try yourself and you will notice that React javascript console triggers an error in the console saying:

Warning:
Cannot update a component (`AppLoadingProvider`) while rendering a different component (`LoadingTriggerA`).
To locate the bad setState() call inside `LoadingTriggerA`,
follow the stack trace as described in https://reactjs.org/link/setstate-in-render
Enter fullscreen mode Exit fullscreen mode

What this means is that, child component can't update one of his parents component's state from within the rendering body.
That's what this warning is telling you.

This is an Anti Pattern because if it was legal, there will be chances that data flow going crazy, and weird stuff will happen, like unnecessary re rendering of the tree.

In our case the Parent is the AppLoadingProvider, which treat LoadingTriggerA and LoadingTriggerB as descendants.

So How to solve that ??

Update the (parent) state inside an useEffect, because useEffect runs after the main rendering phase of a component.

const LoadingTriggerA = () => {
   const [busy, setBusy] = React.useState(false);
   const {showLoading, hideLoading} = useAppLoading();

   React.useEffect(() => {
     if (busy) showLoading();
     else hideLoading();
   }, [busy]);

   return <div>....</div>;
}

Enter fullscreen mode Exit fullscreen mode

Thank you for reading this blog post.
Not clear ? Question ? Ask in comments !!

Do your career a big favor. Join DEV. (The website you're on right now)

It takes one minute, it's free, and is worth it for your career.

Get started

Community matters

Top comments (0)

AWS Security LIVE!

Tune in for AWS Security LIVE!

Join AWS Security LIVE! for expert insights and actionable tips to protect your organization and keep security teams prepared.

Learn More

๐Ÿ‘‹ Kindness is contagious

Explore a sea of insights with this enlightening post, highly esteemed within the nurturing DEV Community. Coders of all stripes are invited to participate and contribute to our shared knowledge.

Expressing gratitude with a simple "thank you" can make a big impact. Leave your thanks in the comments!

On DEV, exchanging ideas smooths our way and strengthens our community bonds. Found this useful? A quick note of thanks to the author can mean a lot.

Okay