Home > front end >  Calling useEffect in a functional component within a functional component causes this message: Rende
Calling useEffect in a functional component within a functional component causes this message: Rende

Time:03-14

first off - Happy Friday!

I just came on here to see if anyone had any input to an issue that I am seeing in my ReactJs application. So I have a functional component renderViews and in that functional component, there are multiple views to render. Then within the renderViews I have another functional component carDetailsView and I try to make a call to an api when that particular component appears(as a modal). requestCarsDetails() should only be called when that component appears so thats why I nested a useEffect hook in the carDetailsView. But that causes an issue:

Rendered more hooks than during the previous render

.Please see code below:

    const renderViews = () = > {
    useEffect(()=> {
     requestCarInfos()
      .then((res) => {
      setCars(cars);
       });
     }, []);

    const carDetailsView = () => {
     useEffect(() => {
       requestCarDetails()
         .then((res) => {
          setDetails(res.details);
           });
      }, []);
       return (<div>carDetailsView</div>)
      }

       return (<div>{determineView()}</div>)
    }

The useEffect that is being used at the top level works fine. The issue only appeared after I added the second useEffect which is in the carDetailsView. Any help or advice is appreciated. Thanks!

CodePudding user response:

Its a rule of hooks.

https://reactjs.org/docs/hooks-rules.html

Only Call Hooks at the Top Level

Don’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function, before any early returns. By following this rule, you ensure that Hooks are called in the same order each time a component renders. That’s what allows React to correctly preserve the state of Hooks between multiple useState and useEffect calls.

React relies on the order in which Hooks are called.

As long as the order of the Hook calls is the same between renders, React can associate some local state with each of them. if we put a Hook call inside a condition we can skip the Hook during rendering, the order of the Hook calls becomes different:

React wouldn’t know what to return for the second useState Hook call. React expected that the second Hook call in this component corresponds to the persistForm effect, just like during the previous render, but it doesn’t anymore. From that point, every next Hook call after the one we skipped would also shift by one, leading to bugs.

This is why Hooks must be called on the top level of our components. If we want to run an effect conditionally, we can put that condition inside our Hook:

use the lint https://www.npmjs.com/package/eslint-plugin-react-hooks

this is a caveat of using functional components, on each render everything inside the functional component gets kind of executed. so react needs to maintain the list of all hooks which have been defined when the component was created. think of it as an array.

on each render, useState will return the value for you. if you understand this, you will understand what stale state also means. ( stale state can happen, when closures occur within these components )

CodePudding user response:

Something like that?

const CarDetailsView = () => {
  React.useEffect(() => {
    console.log("Running CarDetailsView useEffect...") ;
  },[]);
  
  return(
    <div>I amCarDetailsView</div>
  );
};


const Views = () => {
 
  const [showCarDetails,setShowCarDetails] = React.useState(false);
  
  const toggleCarDetails = () => setShowCarDetails(!showCarDetails);
  
  React.useEffect(() => {
    console.log("Running Views useEffect...") ;
  },[]);

  return(
    <div>
      <div>I am Views</div>
      <button onClick={toggleCarDetails}>Toggle car details</button>
      {showCarDetails && <CarDetailsView/>}
    </div>
  );
};


const App = () => {
  return(<Views/>);
};

ReactDOM.render(<App/>,document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script>
<div id="root"/>

  • Related