页面刷新后 React useReducer 钩子状态丢失

Posted

技术标签:

【中文标题】页面刷新后 React useReducer 钩子状态丢失【英文标题】:React useReducer hook state lost after page refresh 【发布时间】:2020-04-30 23:19:30 【问题描述】:

当用户成功登录时,它会将身份验证状态从 null 更改为 true,并且在登陆主页后,当我刷新它设置为的页面时 来自 initialState(AuthState.js) 的默认状态值即使在用户刷新页面后我也想保持状态。我正在使用 hooks reducer

登录.js

      import React,  useState, useContext, useEffect  from "react";
      import AlertContext from "../../context/alert/alertContext";
      import AuthContext from "../../context/auth/authContext";
      const Login = props => 
      const authContext = useContext(AuthContext);
      const  login, isAuthenticated,loading  = authContext;
      useEffect(() => 
      if (isAuthenticated) 
      props.history.push("/");
      
      if (error === "Invalid Credentials") 
      setAlert(error, "danger");
      clearErrors();
      
        // eslint-disable-next-line
      , [error, isAuthenticated, props.history]);
      const [user, setUser] = useState(
      email: "",
      password: ""
      );
      const  email, password  = user;
      const onChange = e => setUser( ...user, [e.target.name]: 
      e.target.value );
      const onSubmit = e => 
      e.preventDefault();
      if (email === "" || password === "") 
      setAlert("Please fill in all fields", "danger");
      removeLoading();
       else 
      login(
      email,
      password
      );
      
      ;
      return (
      <div className="form-container">
      <form onSubmit=onSubmit>
      <div className="form-group">
      <label htmlFor="email">Email Address</label>
      <input type="email" name="email" value=email onChange=onChange
       />
      </div>
      <div className="form-group">
      <label htmlFor="password">Password</label>
      <input
      type="password"
      name="password"
      value=password
      onChange=onChange

              />
            </div>
            <input
              type="submit"
              value="Login"
              className="btn btn-primary btn-block"
            />
          </form>
 </div>
      );
    ;
    export default Login;

AuthState.js

这是初始状态代码

 const AuthState = props => 

  const initialState = 
    //token: localStorage.getItem("token"),
    isAuthenticated: null,
    loading: false,
    user: null,
    error: null

  ;


  const [state, dispatch] = useReducer(authReducer, initialState);
  // Load User
  const loadUser = async () => 
        if (localStorage.token) 
      console.log(localStorage.token)
      setAuthToken(localStorage.token);
    

    try 

      const res = await axios.get("/api/auth");

      dispatch( type: USER_LOADED, payload: res.data );
     catch (err) 

      dispatch( type: AUTH_ERROR );
    
  ;

// Login User
  const login = async formData => 
    const config = 
      headers: 
        "Content-Type": "application/json"
      
    ;

    try 
      const res = await axios.post("api/auth", formData, config);
//console.log(res.data)
      dispatch(
        type: LOGIN_SUCCESS,
        payload: res.data
      );

      loadUser();
     catch (err) 
      dispatch(
        type: LOGIN_FAIL,
        payload: err.response.data.msg
      );
    
  ;
    return (
    <AuthContext.Provider
      value=

        isAuthenticated: state.isAuthenticated,
        loading: state.loading,

        user: state.user,
        error: state.error,
        login,
        logout

      
    >
      props.children
    </AuthContext.Provider>
  );
;

导出默认的AuthState;

authReducer.js 这是减速器钩子代码 进口

  REGISTER_FAIL,
  USER_LOADED,
  AUTH_ERROR,
  LOGIN_SUCCESS,
  LOGIN_FAIL,
  LOGOUT,
  CLEAR_ERRORS,
 from "../types";

export default (state, action) => 
  switch (action.type) 


    case USER_LOADED:

      return 
        ...state,
        isAuthenticated: true,
        loading: false,
        user: action.payload
      ;
       case LOGIN_SUCCESS:

      localStorage.setItem("token", action.payload.token);
      return 
        ...state,
        ...action.payload,
        isAuthenticated: true,
        loading: false
      ;

    case AUTH_ERROR:
    case LOGIN_FAIL:

      localStorage.removeItem("token");

      return 
        ...state,
        token: null,
        isAuthenticated: false,
        loading: false,
        user: null,
        error: action.payload
      ;

        case REMOVE_LOADING:
          return 
            ...state,
            loading: false
          ;
    default:

      return state;
  
;

私人路线

import React,  useContext  from "react";
import  Route, Redirect  from "react-router-dom";
import AuthContext from "../../context/auth/authContext";

const PrivateRoute = ( component: Component, ...rest ) => 
  const authContext = useContext(AuthContext);
  const  isAuthenticated  = authContext;

  return (

    <Route
      ...rest
      render=props =>
        !isAuthenticated ? (
          <Redirect to="/login" />
        ) : (
          <Component ...props />
        )
      
    />
  );
;

export default PrivateRoute;

首页

import React,  useContext, useEffect  from "react";
import AuthContext from "../../context/auth/authContext";

const Home = () => 
  const authContext = useContext(AuthContext);

  useEffect(() => 
    //authContext.setLoading(true);
    authContext.loadUser();

    // eslint-disable-next-line
  , []);
  return (
    <div className="grid-2">
      <div>
        <ContactForm />
      </div>
      <div>
        <ContactFilter />
        <Contacts />
      </div>
    </div>
  );
;

export default Home;  

【问题讨论】:

【参考方案1】:

您可以将您的登录状态传递给 reducer 并更新您的初始状态。 或使用localStorage 喜欢

   let initialState=
        loggedIn: localStorage.getItem('isLoggedin' ) || false;
    

【讨论】:

你能给我举个例子,我如何将状态传递给reducer吗? @user11657014 你能在沙箱中分享你的代码以便我更正 我在主页中添加了 loadUser 函数,该函数使用存储在浏览器中的 JWT 调用后端并在后端进行验证,但它不会在主页中触发并且 isAuthenticated 变为 null 您确定要将身份验证信息存储在本地存储中吗?那安全吗?

以上是关于页面刷新后 React useReducer 钩子状态丢失的主要内容,如果未能解决你的问题,请参考以下文章

使用带有 useReducer() 钩子的 React Context API 有啥优点和缺点?

React TS useContext useReducer 钩子

React 用 useReducer 替换 useState,同时还使用自定义钩子

在表单控制输入中反应 js useReducer 钩子

如何测试组件中的react useContext useReducer调度

React Hooks(钩子函数)