简体   繁体   中英

What is the order for execution of useEffect hook in react?

I am creating a simple react app with router.

I want to get data from the server in one of the child components but data will be fetched only if user is logged in, so in router component I check whether user is logged in or not in useEffect hook. If it is logged in I set a variable which i access afterwords.

In the child component i send the request to server which uses that variable.

but the problem is useEffect of child component is running before useEffect of router component

Sample code for example

My router component

import React, { useEffect } from "react";
import { BrowserRouter, Switch, Route } from "react-router-dom";
import App from "./App";
// import AllWatchers from './components/AllWatchers'

export default function Router() {
  useEffect(() => {
    console.log("router");
  }, []);
  console.log("inrouter");
  return (
    <div>
      <BrowserRouter>
        <Switch>
          <Route exact path="/" component={App} />
          {/* <Route path='/watchers' component={AllWatchers} /> */}
        </Switch>
      </BrowserRouter>
    </div>
  );
}

** my App(child) component **

import React, { useEffect } from "react";
import "./styles.css";

export default function App() {
  useEffect(() => {
    console.log("App");
  }, []);
  console.log("inapp");
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

the output to console for this is

inrouter 
inrouter 
inapp 
inapp 
App 
router 

so my router component is rendering first but useEffect hook of App component is running first why?

you can view code https://codesandbox.io/s/heuristic-gagarin-ego8d?file=/src/App.js:0-319 and check the console

I don't know how to explain why this is happening, but here's a brief solution for you.

import React, { useEffect } from "react";
import "./styles.css";

export default function App() {
  useEffect(() => {
    const timer = setTimeout(() => {
      console.log("App");
    }, 2000);
    return () => clearTimeout(timer);
  }, []);
  console.log("inapp");

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

Got it

inrouter 
inrouter 
inapp 
inapp 
router 
App 

If the user is logged in you could set a state like const [userLoggedIn, setUserLoggedIn] = React.useState(false)

Then the user component could be

{userLoggedIn && <UserComponent />}

This will only render UserComponent if the userLoggedIn.

Another approach would be that you pass userLoggedIn as a prop and then only fetch the data when the that prop is true.

const UserComponent = ({userLoggedIn}) => {
  React.useEffect(() => {
    if(userLoggedIn) {
      // Function that fetchs data.
    }
  }, [userLoggedIn])
}

According to docs first paint for child and parent happen at same time, and order does not matter. Your best bet would be to block the mounting of child component until API call of parent has finished loading.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM