简体   繁体   中英

React useEffect executing last function

I need to have 2 different functions that update 2 different components only once in the beginning. Hence, I'm using useEffect . The code is as follows

const loadCategories = () => {
    getCategories().then((c) => setValues({ ...values, categories: c.data }));
}

const loadStores = () => {
    getStores().then((c) => setValues({ ...values, stores: c.data }));
}

useEffect(() => {
  loadStores();
  loadCategories();
}, []);

Both the functions are setting the values of the dropdown elements

The problem is though both functions are exectued, only loadCategories() function logic is reflected in the UI. How to make both functions logic reflect in the UI?

Wait for both promises to resolve and then use the data from both to update your state, combined in whatever way you see fit.

useEffect(() => {
    Promise.all([getCategories(), getStores()]).then(([categories, stores]) => {
      setValues({categories, stores})
    });
}, []);

The problem with what you had before (as you experienced) is that values is always the value at the point at which useState was run on this render.

If you really want to do the updates separately, than you can look into useReducer: https://reactjs.org/docs/hooks-reference.html#usereducer

Promise and useEffect can be challenging as the component might dismount before you promise is full-filled.

Here is a solution which works quite well:

useEffect(() => {
  let isRunning = true;
  Promise.all([ 
    getCategories(),
    getStores()
  ]).then(([stores, categories]) => {
    // Stop if component was unmounted:
    if (!isRunning) { return }
    // Do anything you like with your lazy load values:
    console.log(stores, categories)
  });
  return () => {
    isRunning = false;
  }
}, []);

You are lying to React about dependencies. Both your functions depend on the values state variable. That's also why it does not work: When the hooks get run, values gets closured, then when setValues runs values changes (gets set to a new object), however inside the closure it is still referencing the old values.

You can easily resolve that by passing a callback to setValues , this way you do not have a dependency to the outside and the values update is atomic:

 setValues(values => ({ ...values, stores: c.data }));

first better practice to add those function in useEffect or to wrap them in useCallback hook. second both or your function are promises so each may not resolve at same time and when you trying to update state values will keep it initial value that why your first function is not reflecting in the ui instead use setState callback to get the previous state like this:

useEffect(() => {
const loadCategories = () => {
    getCategories().then((c) => setValues(prevState=>({ ...prevState, categories: c.data })));
}

const loadStores = () => {
    getStores().then((c) => setValues(prevState=>({ ...prevState, stores: c.data })));
}
  loadStores();
  loadCategories();
}, []);

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