setState не обновляет состояние при первоначальной отправке, только при последующих отправках - PullRequest
0 голосов
/ 02 октября 2019

Я пытаюсь использовать сессионное хранилище для установки некоторых данных, Это не работает в первый раз, но работает во второй раз.

  const login = async (email, password) => {
    try {
        const user = await loginUser({
          variables: {
            email,
            password
          }
        });

        const { userId, token, expiresIn } = user.data.loginUser;

        setUserData({
          token: token,
          userId: userId,
          expiresIn: expiresIn
        })

        sessionStorage.setItem('interdevs-data', JSON.stringify({ 
          "token": userData.token, 
          "userId": userData.userId, 
          "expiresIn": userData.expiresIn 
        }));
    } catch(err) {
      setLoginErr(err);
    };
  };


Я ожидаю, что это setState при первоначальной отправке, но все в порядке, когда я нажимаю кнопку отправить снова

Ответы [ 2 ]

1 голос
/ 02 октября 2019

Метод setUserData() является асинхронным, что означает, что ничто не мешает написанному коду после его выполнения до завершения его собственной логики. Это верно для всех методов обновления состояния.

Вероятно, происходит то, что блок sessionStorage.setItem() запускается до того, как вы полностью обновите состояние в предыдущем блоке. Так что в localStorage не нужно ничего сохранять в первый раз. Но при последующих попытках состояние обновляется с помощью токена / пользовательской информации из предыдущего обновления.

Существует несколько способов решения этой проблемы:

1) Это просто обновить локальное хранилищес переменными, которые вы создали, вместо ожидания завершения состояния:

  const login = async (email, password) => {
    try {
        const user = await loginUser({
          variables: {
            email,
            password
          }
        });

        const { userId, token, expiresIn } = user.data.loginUser;

        setUserData({
          token: token,
          userId: userId,
          expiresIn: expiresIn
        })

        sessionStorage.setItem('interdevs-data', JSON.stringify({ 
          "token": token, 
          "userId": userId, 
          "expiresIn": expiresIn 
        }));
    } catch(err) {
      setLoginErr(err);
    };
  };

2) Используйте useEffect() для обновления localStorage при изменении состояния.

  useEffect(() => {
        sessionStorage.setItem('interdevs-data', JSON.stringify({ 
          "token": userData.token, 
          "userId": userData.userId, 
          "expiresIn": userData.expiresIn 
        }));
  }, [user]) //swap user with whatever you called your state

  const login = async (email, password) => {
    try {
        const user = await loginUser({
          variables: {
            email,
            password
          }
        });

        const { userId, token, expiresIn } = user.data.loginUser;

        setUserData({
          token: token,
          userId: userId,
          expiresIn: expiresIn
        })

    } catch(err) {
      setLoginErr(err);
    };
  };
0 голосов
/ 02 октября 2019

useState в React Hook также равно asynchronous, как this.setState в React Component.

Итак, вы можете попробовать:

const login = async (email, password) => {
    try {
        const user = await loginUser({
          variables: {
            email,
            password
          }
        });

        const { userId, token, expiresIn } = user.data.loginUser;

        // setUserData({
        //   token: token,
        //   userId: userId,
        //   expiresIn: expiresIn
        // })
        // userData here not yet updated
        sessionStorage.setItem('interdevs-data', JSON.stringify({ 
          "token": token, 
          "userId": userId, 
          "expiresIn": expiresIn 
        }));
        // In your case, you can direct access to user.data.loginUser. Don't need use setUserData
    } catch(err) {
      setLoginErr(err);
    };
  };

Или, если вы все еще хотите использовать setUserData, попробуйте применить useEffect как:

const login = async (email, password) => {
    try {
        const user = await loginUser({
          variables: {
            email,
            password
          }
        });
        const { userId, token, expiresIn } = user.data.loginUser;
        setUserData({
           token: token,
           userId: userId,
           expiresIn: expiresIn
        })
    } catch(err) {
      setLoginErr(err);
    };
  };

useEffect(() => {
    sessionStorage.setItem('interdevs-data', JSON.stringify({ 
          "token": userData.token, 
          "userId": userData.userId, 
          "expiresIn": userData.expiresIn 
        }));
}, [userData])
...