如何使用本地存储、react hooks 和 Context Provider 保持状态持久

EzJ*_*zJS 5 reactjs react-hooks use-effect

我正在我的应用程序中实施身份验证,我遇到的问题是刷新时状态不持久,因此我被重定向回登录屏幕。如何使用 React Hooks 检查是否有authToken来local storage让我在刷新时保持登录状态。

这是我的受保护路由,用于检查身份验证令牌

<Route
    {...rest}
    render={
        props=>
            authTokens ? (
                <Component {...props}/>
            ) : (
                <Redirect
                    to ={
                        {
                            pathname: '/login',
                            state: {
                                from: props.location
                            }
                        }
                    }
                />
Run Code Online (Sandbox Code Playgroud)

这是我的登录页面功能

 function Login(props) {
const [isLoggedIn, setLoggedIn] = useState(false);
const [isError, setIsError] = useState(false);
const [firstName, setUserName] = useState("");
const [password, setPassword] = useState("");
const { setAuthTokens } = useAuth();

function postLogin() {
    axios.post("http://10.6.254.22:5000/userinformation/login", {
      firstName,
      password
    }).then(result => {
      if (result.status === 200) {
        console.log('You have been logged in as user: ' +result.data[0].firstName)
        setAuthTokens(result.data);
        setLoggedIn(true);
      } else {
        setIsError(true);
      }
    }).catch(e => {
      setIsError(true);
    });
  }


  if (isLoggedIn) {
    return <Redirect to="/" />;
  }
Run Code Online (Sandbox Code Playgroud)

下面是我的Hook,其中包含状态

    const [authTokens, setAuthTokens] = useState();

  const setTokens = (data) => {
    localStorage.setItem("authTokens", JSON.stringify(data));
    setAuthTokens(data);
  }

  useEffect(()=> {
    let jsonToken = localStorage.getItem('authTokens', JSON.stringify(authTokens))
    console.log('JSON TOKEN  -----' + jsonToken)
    setAuthTokens(jsonToken)
  })
Run Code Online (Sandbox Code Playgroud)

如何使用加载时的变量设置状态authTokens ,local storage以便当我刷新状态时不为空,这样我就不会在页面重新加载时注销。还要提一下上下文提供者的设置如下:

<AuthContext.Provider value={{ authTokens, setAuthTokens: setTokens}}>
   <ProtectedRoute path="/" exact component={ProfileBox}/>
</AuthContext.Provider>
Run Code Online (Sandbox Code Playgroud)

Ric*_*lez 5

您可以创建一个钩子来检查 是否localstorage包含token,如果不存在,则用户未经过身份验证,因此您可以将他重定向到logIn,否则用户可以访问ProtectedRoutes.

也许您可以在组件内重用您的钩子ProtectedRoute并在那里处理它。

保护路由

假设您的组件Login是您想要重定向的页面(如果用户不是)auth。假设您正在使用react-router或 某种东西来处理路由和重定向。

const ProtectedRoute = ({component, ...options}) => {
   const [isAuth ] = useAuth();
   let conditionalComponent = Login;
   if( isAuth ){
     conditionalComponent = component;
   }
   return <Route {...options} component={conditionalComponent} />
}
Run Code Online (Sandbox Code Playgroud)

使用验证


const useAuth = () => {
 let [isAuth, handleAuthorized] = useState(false);

 useEffect( () => {
   if( checkLocalStorageToken() ){
    handleAuthorized( true );
   }  
   else {
    handleAuthorized(false)
   }
  return [ isAuth ]
 }, [ checkLocalStorageToken() ]);

}
Run Code Online (Sandbox Code Playgroud)

我已经使用了这种模式并且效果很好,我希望我可以分享主要思想,以便您可以在您的案例中实现它。


vic*_*.ja 2

问题是,authTokens当undefined您的组件挂载时,受保护的路由的逻辑正在评估Redirect您的代码部分,导致重定向到/login。

React 将删除componentWillMount钩子,因此,我发现这个特定问题的解决方案是还检查 中的令牌localStorage,而不仅仅是检查状态authTokens。

这样,您的代码将能够评估您是否拥有令牌(甚至在第一个组件更新之前)。

您的代码Protected Route可能如下所示:

<Route
    {...rest}
    render={
        props=>
            (authTokens || localStorage.getItem("authTokens")) ? (
                <Component {...props}/>
            ) : (
                <Redirect
                    to ={
                        {
                            pathname: '/login',
                            state: {
                                from: props.location
                            }
                        }
                    }
                />
Run Code Online (Sandbox Code Playgroud)

其他可能的解决方案是:

  • 使用上下文
  • 使用 Redux

但我认为如果你只是想保护私有路由,这个解决方案就足够了