React Hooks, setState не работает с вызовом asyn c .map - PullRequest
1 голос
/ 05 апреля 2020

Итак, я пытаюсь изменить состояние в своем компоненте, получив список пользователей для вызова api.get для получения данных от этих пользователей и добавления нового массива со следующим кодом:

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]);
        });
    }

но состояние devs всегда возвращает пустой массив, что я могу сделать, чтобы в нем были данные о реальных пользователях?

Ответы [ 4 ]

0 голосов
/ 05 апреля 2020

вы звоните setDevs в асин c выполнение л oop. Вот обновленная функция handleDevs.

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]);
}
0 голосов
/ 05 апреля 2020

Проблема в том, что setDevs использует devs, то есть версию devs, когда определено handleDevs. Поэтому setDevs действительно будет включать в себя только данные последнего вызова setDevs.

Чтобы исправить это, вы можете использовать версию обратного вызова setDevs, например:

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

Кроме того, поскольку вы не пытаетесь создать новый массив, использование map не является семантически лучшим выбором l oop. Попробуйте вместо него использовать обычный for l oop или forEach l oop.

0 голосов
/ 05 апреля 2020

Проблема, с которой вы столкнулись, заключается в том, что вы каждый раз устанавливали dev на основе данных оригинального рендера из-за замыкания вокруг функции handleDevs. Я считаю, что это должно помочь решить проблемы, возникающие при использовании метода обратного вызова с использованием setDevs. Это также решает некоторые проблемы с массивами зависимостей и устареванием в хуке useEffect. Обычно использование // 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]);
}
0 голосов
/ 05 апреля 2020

Вам необходимо понять, как React работает за кулисами.

Короче говоря, он сохраняет все «наборы» до тех пор, пока не завершит цикл, и только после этого фактически обновляет каждое состояние.

I думаю, почему вы не видите текущее состояние обновлено.

Для лучшего понимания прочитайте этот пост: Средняя статья

...