简体   繁体   English

React Hooks,setState 不适用于 async.map 调用

[英]React Hooks, setState not working with an async .map call

So, I'm trying to change a state in my component by getting a list of users to call an api.get to get data from these users and add on an new array with the following code:因此,我试图通过获取用户列表来调用 api.get 从这些用户获取数据并使用以下代码添加新数组来更改我的组件中的 state:

function MembersList(props) {
    const [membersList, setMembersList] = useState(props.members);
    const [devs, setDevs] = useState([]);

    useEffect(() => {
        let arr = membersList.map((dev) => {
            return dev.login;
        });

        handleDevs(arr);
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [membersList]);

    function handleDevs(membersArr) {
        membersArr.map(async (dev) => {
            let { data } = await api.get(`/users/${dev}`);

              /** If i console.log data here i actualy get the data from the user 
                  but i think theres something wrong with that setDevs([...devs, data]) call
              **/

            setDevs([...devs, data]);
        });
    }

but the devs state always return an empty array, what can I do to get it to have the actual users data on it?但是devs人员 state 总是返回一个空数组,我该怎么做才能让它拥有实际的用户数据?

You need to understand how React works behind scenes.你需要了解 React 是如何在幕后工作的。

In short, it saves all the "sets" until it finishes the cycle and just after that actually update each state.简而言之,它会保存所有“集合”,直到完成循环,然后才实际更新每个 state。

I think that why you do not see the current state updated.我想这就是为什么你没有看到当前 state 更新的原因。

For better understanding read this post: Medium article为了更好地理解这篇文章: Medium article

The issue is that setDevs uses devs which is the version of devs when handleDevs is defined.问题是setDevs使用devs ,这是定义handleDevs时的devs版本。 Therefore setDevs will really only incorporate the data from the last time setDevs is called.因此setDevs实际上只会合并上次调用setDevs的数据。

To fix this you can use the callback version of setDevs , like so:要解决此问题,您可以使用setDevs的回调版本,如下所示:

setDevs(prevDevs => [...prevDevs, data])

Also since you are not trying to create a new array, using map is not semantically the best loop choice.此外,由于您没有尝试创建新数组,因此使用map在语义上并不是最佳循环选择。 Consider using a regular for loop or a forEach loop instead.考虑改用常规for循环或forEach循环。

The issue you were having is because you were setting devs based on the data from the original render every time due to the closure around handleDevs function.您遇到的问题是,由于handleDevs function 周围的关闭,您每次都根据原始渲染中的数据设置开发人员。 I believe this should help take care of the issues you were having by using the callback method of using setDevs.我相信这应该有助于通过使用 setDevs 的回调方法来解决您遇到的问题。 This also takes care of some issues with the dependency arrays and staleness in the useEffect hook.这也解决了依赖 arrays 和 useEffect 挂钩中的一些问题。 Typically using // eslint-disable-next-line react-hooks/exhaustive-deps should be your last resort.通常使用// eslint-disable-next-line react-hooks/exhaustive-deps应该是你最后的手段。

function MembersList(props) {
    // this isn't needed unless you are using it separately
    const [membersList, setMembersList] = useState(props.members);
    const [devs, setDevs] = useState([]);

    useEffect(() => {
        let arr = membersList.map((dev) => dev.login);
        arr.forEach(async (dev) => {
            let { data } = await api.get(`/users/${dev}`);
            setDevs((devs) => [...devs, data]);
        })
    }, [membersList]);
}

you call setDevs in the async execution loop.您在异步执行循环中调用setDevs Here is the updated handleDevs function.这是更新的handleDevs function。

function handleDevs(membersArr) {
    const arr = membersArr.map(async (dev) => {
        let { data } = await api.get(`/users/${dev}`);
        return data;
          /** If i console.log data here i actualy get the data from the user 
              but i think theres something wrong with that setDevs([...devs, data]) call
          **/
    });
    setDevs([...devs, ...arr]);
}

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

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