简体   繁体   English

React useEffect 执行最后一个 function

[英]React useEffect executing last function

I need to have 2 different functions that update 2 different components only once in the beginning.我需要有 2 个不同的功能,在开始时只更新 2 个不同的组件一次。 Hence, I'm using useEffect .因此,我正在使用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.问题是虽然这两个函数都执行了,但只有loadCategories() function 逻辑反映在 UI 中。 How to make both functions logic reflect in the UI?如何让这两个功能逻辑都反映在 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.等待两个承诺解决,然后使用两者中的数据更新您的 state,以您认为合适的任何方式组合。

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.您之前遇到的问题(正如您所经历的那样)是values始终是在此渲染上运行useState时的值。

If you really want to do the updates separately, than you can look into useReducer: https://reactjs.org/docs/hooks-reference.html#usereducer如果您真的想单独进行更新,则可以查看 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. Promise 和useEffect可能具有挑战性,因为组件可能会在 promise 装满之前卸下。

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.你在向 React 撒谎关于依赖关系。 Both your functions depend on the values state variable.您的两个函数都取决于 state 变量的values 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.这也是它不起作用的原因:当钩子运行时, values会被关闭,然后当setValues运行时, 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轻松解决该问题,这样您就不会依赖外部并且值更新是原子的:

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

first better practice to add those function in useEffect or to wrap them in useCallback hook.第一个更好的做法是将那些 function 添加到 useEffect 或将它们包装在useCallback钩子中。 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: 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();
}, []);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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