React useState в контексте не обновляется

#javascript #reactjs #react-context #react-state-management

#язык JavaScript #реагирует на #реагировать-контекст #реагировать-государственное управление

Вопрос:

Я использую React для создания страницы входа в систему, которая после входа в систему должна отслеживать, вошел ли пользователь в систему. Я решил, что использовать контекст и состояние реакции будет проще, чем использовать что-то такое большое и сложное, как Redux.

Я создал функцию входа в систему, которая работает, и после успешного входа в систему она должна обновить мое состояние в моем контексте. Вход в систему работает (я получаю статус 200), но мое состояние не обновляется в моем контексте.

Мой «AuthContext.jsx» выглядит так

 import React, { createContext, useState } from "react"; import { login, register } from "../API/apiMethods";  export const AuthContext = createContext();  export const AuthProvider = ({ children }) =gt; {  const [authenticated, setAuthenticated] = useState(false);   const authSetter = (state) =gt; {  setAuthenticated(state);  };   const authGetter = () =gt; {  return authenticated;  };   return (  lt;AuthContext.Provider  value={{  authSetter,  authGetter,  login,  register,  }}  gt;  {children}  lt;/AuthContext.Providergt;  ); }; 

Моя функция входа в систему выглядит следующим образом

 /**  * @description Handles login  * @param {String} email  * @param {String} password  * @returns {Boolean}  */ export const login = async(email, password) =gt; {  try {  let authenticated = false;  await fetch(BASE_URL   "login", {  method: "POST",  credentials: "include",  headers: {  "Content-Type": "application/json"  },  body: JSON.stringify({  email,  password  }),  }).then((res) =gt; {  authenticated = res.status === 200 ? true : false;  });  return authenticated;  } catch (err) {  console.log(err);  return false;  } }; 

И в своей форме входа в систему я пытаюсь обновить логическое значение аутентификации после успешного входа в систему

 const {  login,  authSetter,  authGetter } = useContext(AuthContext); const submit = async(e) =gt; {  e.preventDefault();   await login(email, password)  .then((authSuccess) =gt; {  if (authSuccess) {  console.log("login successfull");  authSetter(true);  }  })  .then(() =gt; console.log(authGetter())); }; 

С помощью этого кода я ожидал, что вывод консоли будет печатной строкой с «успешно вошел в систему» и печатным логическим значением true. Но, похоже, мое состояние не было обновлено, хотя я и позвонил сеттеру.

вывод моей консоли

Я не знаю, почему он не обновляется, может ли кто-нибудь мне помочь?

Комментарии:

1. setAuthenticated является асинхронной функцией,т. е. она не обновляется немедленно, поэтому вы получаете ложь в журнале. Попробуйте записать значение вне submit функции

Ответ №1:

Этот фрагмент кода делает именно то, что он должен делать. Когда вы обновляете состояние, это происходит не сразу.

 const submit = async(e) =gt; {  e.preventDefault();   await login(email, password)  .then((authSuccess) =gt; {  if (authSuccess) {  console.log("login successfull");  authSetter(true);  }  })  .then(() =gt; console.log(authGetter())); };  

Когда вы вызываете authSetter(true); , обновление состояния ставится в очередь, и как только обратный вызов завершается, оно переходит к следующему then в цепочке, у которого есть ваш authGetter() . Теперь обновление состояния происходит не сразу, как я объяснил, оно ставится в очередь. Поэтому, когда выполняется последний then обратный вызов, обновление состояния, поставленное в очередь, не произошло, и вы все еще видите false , какое значение является старым.

Вы можете выполнить рефакторинг AuthProvider следующим образом: нет необходимости заключать сеттер в функцию, так как это создаст новый экземпляр функции при обновлении состояния ( useState с другой стороны, возвращает запомненное значение функции сеттера), и вы можете просто вернуть authenticated состояние без геттера, у которого снова та же проблема.

 import React, { createContext, useState } from "react"; import { login, register } from "../API/apiMethods";  export const AuthContext = createContext();  export const AuthProvider = ({ children }) =gt; {  const [authenticated, setAuthenticated] = useState(false);   return (  lt;AuthContext.Provider  value={{  setAuthenticated,  authenticated,  login,  register,  }}  gt;  {children}  lt;/AuthContext.Providergt;  ); };  

В своей форме вы можете дополнительно useEffect проверить, успешно ли вы вошли в систему. он useEffect будет запущен, когда authenticated состояние будет обновлено.

 const {  login,  setAuthenticated,  authenticated } = useContext(AuthContext);  const submit = async(e) =gt; {  e.preventDefault();  const authSuccess = await login(email, password);  if (authSuccess) {  console.log("login successfull");  authSetter(true);  } };  useEffect(() =gt; {  console.log(authenticated); }, [authenticated]);