How do I prevent the useEffect of a child component from igniting?

Asked 1 years ago, Updated 1 years ago, 299 views

Creating web tools with React.
Is it possible to prevent the useEffect of the child components from igniting when the parent component changes to something else?

We have prepared the smallest sample.
CodeSandbox: https://codesandbox.io/s/jovial-kowalevski-lkdbx

functionComponentA(props){
  return(
    <div style={{backgroundColor:"pink"}}>
      <p>Component A</p>
      {props.children}
    </div>
  );
}

functionComponentB(props){
  return(
    <div style={{backgroundColor:"skyblue"}}>
      <p>Component B</p>
      {props.children}
    </div>
  );
}

functionCommonComponent(){
  React.useEffect(()=>{
    console.log("useEffect is running in CommonComponent.");
  }, []);
  return(<div>Common component.</div>);
}

functionApp(){
  const [ab, setAB] = React.useState(true);
  const ParentComponent=ab?ComponentA:ComponentB;
  return(
    <React.Fragment>
      <label>
        <input
          type="checkbox"
          checked = {ab}
          onChange={(event)=>{
            setAB(event.target.checked);
          }}
        />
        Switch A/B
      </label>

      <ParentComponent>
        <CommonComponent/>
      </ParentComponent>
    </React.Fragment>
  );
}

constrootElement= document.getElementById("root");
ReactDOM.render(
  <React.StrictMode>
    <App/>
  </React.StrictMode>,
  rootElement
);
.App{
  font-family:sans-serif;
  text-align:center;
}
<script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js">/script>

<divid="root"></div>

Each time you switch SSwitch A/B 」, the useEffect in CommonComponent fires, and the console prints とuseEffect is running in CommonComponent. "
At this time, the actual application fetches data from the server, which is expensive to execute.
Is it possible to avoid re-running useEffect in some way, as this useEffect is essentially unaffected by the parent, as you set an empty array in the dependency list?

Component A, B are actually forms, and CommonComponent is part of a form that summarizes several check boxes.

reactjs react-jsx

2022-09-30 21:55

1 Answers

This may be a problem that has already been solved, but I will write an answer for your reference only.

If the parent component is re-rendered, the child component will always be re-rendered, so if the structure cannot be changed to a sibling component, the code will be difficult.

This time, we don't want to prevent re-rendering, but we want to run a heavy fetch only once, so there is also a way to deploy a state management library such as Redux

However, in this case, only the information in the questionnaire is

So, isn't this useEffect supposed to be the responsibility of App?

If so, you can define the useCommonStatus() of your own hook as follows, render ParentComponent and CommonComponent with the responsibility component (App) to pass useEffect to fetch.

Create Your Own Hook – React
https://ja.reactjs.org/docs/hooks-custom.html

//proprietary hook
function useCommonStatus(){
  const [common, setCommon] = React.useState (null);

  React.useEffect(()=>{
    console.log("useEffect is running.");

    setTimeout(()=>{
      console.log("useEffect completed.");
      setCommon ([1, 2, 3, 4, 5]);
    }, 5000);
  }, []);

  return common;
}

functionComponentA(props){
  return(
    <div style={{backgroundColor:"pink"}}>
      <p>Component A</p>
      {props.children}
    </div>
  );
}

functionComponentB(props){
  return(
    <div style={{backgroundColor:"skyblue"}}>
      <p>Component B</p>
      {props.children}
    </div>
  );
}

functionCommonComponent (props) {
  return(<div>Common component values: {props.common?props.common.join(): 'Loading...'}</div>);
}

functionApp(){
  const common=useCommonStatus();

  const [ab, setAB] = React.useState(true);
  const ParentComponent=ab?ComponentA:ComponentB;
  return(
    <React.Fragment>
      <label>
        <input
          type="checkbox"
          checked = {ab}
          onChange={(event)=>{
            setAB(event.target.checked);
          }}
        />
        Switch A/B
      </label>

      <ParentComponent>
        <CommonComponent common={common}/>
      </ParentComponent>
    </React.Fragment>
  );
}

constrootElement= document.getElementById("root");
ReactDOM.render(
  <React.StrictMode>
    <App/>
  </React.StrictMode>,
  rootElement
);
.App{
  font-family:sans-serif;
  text-align:center;
}
<script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js">/script>

<divid="root"></div>


2022-09-30 21:55

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.