How do I keep state persistant using local storage, react hooks, and Context Provider

早过忘川 提交于 2021-02-07 20:01:25

问题


I'm implementing authentication into my app, the issue I am having is on refresh the state is not persistent so I get redirected back to the login screen. How can I use React Hooks to check if there is an authToken in local storage to keep me logged in on refresh.

This is My Protected Route That checks for auth tokens

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

This is my Login page Function

 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="/" />;
  }

Below is my Hook that contains the state

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

How can i set the state authTokens with the local storage variable on load so that when I refresh the state isnt empty so i dont get logged out on page reload. Also to mention The context provider is set up as so:

<AuthContext.Provider value={{ authTokens, setAuthTokens: setTokens}}>
   <ProtectedRoute path="/" exact component={ProfileBox}/>
</AuthContext.Provider>

回答1:


The problem is that authTokens is undefined when your component mounts, so the logic of your Protected route is evaluating to the Redirect portion of your code, causing the redirection to /login.

React will remove componentWillMount hook, so, the solution I found to this specific problem, is to check also for the token in the localStorage, instead of just checking for the state authTokens.

This way, your code will be able to evaluate that you have the token (even before the first component update).

The code of your Protected Route may look like this:

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

Other possible solutions are:

  • Using Context
  • Using Redux

But I think that if you just want to protect private routes, this solution is sufficient




回答2:


You can create a hook that checks that the localstorage contains the token, if it doesn't exist the user isn't authenticated, so you can redirect him to logIn, else the user can access the ProtectedRoutes.

Maybe you can reuse your hook inside the ProtectedRoute component and handle it just there.

ProtectedRoute

Lets say that your component Login is the page that you want to redirect if the user isn't auth. And lets say that you are using react-router or something to handle the routes and redirections.

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

useAuth


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

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

}

I've been used this pattern and works good, i hope that i can share the main idea so you can implement it in your case.



来源:https://stackoverflow.com/questions/58751020/how-do-i-keep-state-persistant-using-local-storage-react-hooks-and-context-pro

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!