如何在刷新时保持身份验证状态?

时间:2021-02-19 07:09:44

标签: reactjs firebase react-router react-router-dom

我正在为我的应用使用 Firebase 身份验证。我使用了 here 中的 useAuth 钩子。与关于重定向 (Auth) 的 react-router guide 集成。

SignIn,SignOut 函数按预期工作。但是当我尝试刷新页面时。它再次重定向到 /login

我的预期:通过身份验证后重定向到 / 路由。

我尝试在 PrivateRoute.js 中添加此代码

  if (auth.loading) {
    return <div>authenticating...</div>;
  }

所以我可以在不重定向到 /login 的情况下刷新页面,但是当点击 authenticating... 按钮时它只显示 log out

这是我的代码:https://codesandbox.io/s/frosty-jennings-j1m1f?file=/src/PrivateRoute.js

我错过了什么?谢谢!

2 个答案:

答案 0 :(得分:1)

问题

似乎您没有充分呈现“正在验证”的加载状态。

我认为,当初始身份验证检查解决时,您没有正确清除 loading 中的 useEffect 中的 useAuth 状态。

解决方案

每当启动身份验证检查或操作时将 loading 设置为真,并在检查或操作完成时清除。

使用身份验证

function useProvideAuth() {
  const [loading, setLoading] = useState(true); // <-- initial true for initial mount render
  const [user, setUser] = useState(null);

  // Wrap any Firebase methods we want to use making sure ...
  // ... to save the user to state.
  const signin = (email, password) => {
    setLoading(true); // <-- loading true when signing in
    return firebase
      .auth()
      .signInWithEmailAndPassword(email, password)
      .then((response) => {
        setUser(response.user);
        return response.user;
      })
      .finally(() => setLoading(false)); // <-- clear
  };

  const signout = () => {
    setLoading(true); // <-- loading true when signing out
    return firebase
      .auth()
      .signOut()
      .then(() => {
        setUser(false);
      })
      .finally(() => setLoading(false)); // <-- clear
  };

  // Subscribe to user on mount
  // Because this sets state in the callback it will cause any ...
  // ... component that utilizes this hook to re-render with the ...
  // ... latest auth object.
  useEffect(() => {
    const unsubscribe = firebase.auth().onAuthStateChanged((user) => {
      if (user) {
        setUser(user);
      } else {
        setUser(false);
      }
      setLoading(false); // <-- clear
    });

    // Cleanup subscription on unmount
    return () => unsubscribe();
  }, []);

  // Return the user object and auth methods
  return {
    loading,
    user,
    signin,
    signout
  };
}

检查 PrivateRoute 中的加载状态

function PrivateRoute({ children, ...rest }) {
  const auth = useAuth();

  if (auth.loading) return "authenticating";

  return (
    <Route
      {...rest}
      render={({ location }) =>
        auth.user ? (
          children
        ) : (
          <Redirect
            to={{
              pathname: "/login",
              state: { from: location }
            }}
          />
        )
      }
    />
  );
}

演示

Edit how-to-keep-authenticated-state-on-refresh

答案 1 :(得分:0)

试试这个方法,它对我有用:

const mapStateToProps = state => ({
  ...state
});

function ConnectedApp() {
     const [auth, profile] = useAuth()

     const [isLoggedIn, setIsLoggedIn] = useState(false)

     useEffect(() => {

       if (auth && auth.uid) {
          setIsLoggedIn(true)
       } else {
          setIsLoggedIn(false)
       }
     }, [auth, profile]);

     return (<Router>
       <Redirect to="/app/home"/>
       <div className="App">
       <Switch>

        <Route path="/home"><Home/></Route>
        <Route path="/login"><Login styles={currentStyles}/></Route>
        <Route path="/logout"><Logout styles={currentStyles}/></Route>
        <Route path="/signup" render={isLoggedIn
            ? () => <Redirect to="/app/home"/>
            : () => <Signup styles={currentStyles}/>}/>
        <Route path="/profile" render={isLoggedIn
            ? () => <Profile styles={currentStyles}/>
            : () => <Redirect to="/login"/>}/>

      </Switch>
    </div>
  </Router>);
    }
const App = connect(mapStateToProps)(ConnectedApp)

export default App;