【问题标题】:ReactJS authentication routing component rendering before useEffect hook completes在 useEffect 钩子完成之前 ReactJS 认证路由组件渲染
【发布时间】:2021-06-24 02:25:13
【问题描述】:

我正在尝试使用 Firebase 身份验证来实现受保护的页面。我创建了一个典型的 PrivateRoute 组件,该组件应该只在用户登录时显示该页面,或者如果用户未登录则将用户重定向到登录页面。

我使用 App.js 中的 useEffect 挂钩将身份验证状态存储在全局状态中。经过大量阅读和研究,我了解到 useEffect 仅在 Child 组件加载后完成。

话虽如此,我不知道如何将身份验证从 App 传递到 PrivateRoute。使用我当前的代码,仅在 PrivateRoute 将用户推送到登录页面后,身份验证状态才会注册为 true。将不胜感激。

App.js

//context
 const [{user, authenticated}, dispatch] = useStateValue();

  useEffect(() => {
    auth.onAuthStateChanged((authUser) => {
      console.log("THE USER IS >>> ", authUser);

      if (authUser) {
        dispatch({
          type: "SET_USER",
          user: authUser,
        });
        dispatch({
          type: "SET_AUTH",
          authenticated: true,
        })

      } else {
        // the user is logged out
        dispatch({
          type: "SET_USER",
          user: null,
        });
        dispatch({
          type: "SET_AUTH",
          authenticated: false,
        })
      }
    });
  }, []);

return (
    <Router>
      <div className="app">
          <PrivateRoute exact isAuth={authenticated} path="/account/create-store" component={CreateAccount} />
      </div>
    </Router>
)

PrivateRoute.js

import { Route, Redirect } from 'react-router';
import { useStateValue } from './StateProvider';

function PrivateRoute ({ isAuth: isAuth, component: Component, ...rest }) {
    const [{authenticated}, dispatch] = useStateValue();

    return (
        <Route {...rest} render={(props) => {
            if (isAuth)  {
                return <Component />
            } else {
                return (
                <Redirect to={{ pathname:"/login", state: {from: props.location }}} />
                );
            }
          }} />
    )
}

export default PrivateRoute

reducer.js

export const initialState = {
    user: null,
    authenticated: false,
};

const reducer = (state, action) => {
    console.log(action)
    switch(action.type) {
        case "SET_USER":
            return {
                ...state,
                user: action.user,
            }

        case "SET_AUTH":
            return {
                ...state,
                authenticated: action.authenticated,
            }


        default:
            return state;
}}

export default reducer;

【问题讨论】:

  • 这不是一个真正的答案,但我发现了这篇文章 (stackoverflow.com/questions/58769189/…),实际上它可以让事情正常进行。不过,我仍然非常感谢您解释为什么我的方法存在缺陷。

标签: javascript reactjs react-router react-hooks react-context


【解决方案1】:

我无法重现您的确切问题,但我认为您的 PrivateRoute 是错误的。试试下面的例子。

function PrivateRoute({ isAuth, component: Component, ...rest }) {
  if (!isAuth) {
    return <Redirect to={{ pathname:"/login", state: {from: props.location }}} />;
  }

  return <Route component={Component} {...rest} />;
}

export default PrivateRoute;

使用 isLoading 状态变量,因此在检查 firebase.auth().onAuthStateChanged 之前不会重定向。

const [{user, authenticated}, dispatch] = useStateValue();
const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    auth.onAuthStateChanged((authUser) => {
      console.log("THE USER IS >>> ", authUser);

      if (authUser) {
        dispatch({
          type: "SET_USER",
          user: authUser,
        });
        dispatch({
          type: "SET_AUTH",
          authenticated: true,
        })

      } else {
        // the user is logged out
        dispatch({
          type: "SET_USER",
          user: null,
        });
        dispatch({
          type: "SET_AUTH",
          authenticated: false,
        })
      }
      setIsLoading(false);
    });
  }, []);

if(isLoading) {
  return <div>Loading...</div>
}

return (
    <Router>
      <div className="app">
          <PrivateRoute exact isAuth={authenticated} path="/account/create-store" component={CreateAccount} />
      </div>
    </Router>
)

【讨论】:

  • 在这种情况下,它无法编译,因为 props 不再是参数并且现在未定义。我将减速器文件添加到帖子中,但我不认为这是问题的原因。我曾尝试将身份验证设为本地状态,我只需手动切换真假,这似乎可行。但是当我在钩子中使用 firebase.auth().onAuthStateChanged 时,它只会在检查 PrivateRoute 后更新上下文状态,所以它每次都会重定向我登录,因为 authenticated=false。
  • 我已经更新了答案,现在在 firebase.auth().onAuthStateChanged 运行之前检查之前不会重定向您。是的,您需要删除重定向内的道具。如果你想在登录后重定向用户,你可以使用 react-router-dom 提供的 useHistory 钩子之类的东西。
  • 非常感谢您,好心的先生。
猜你喜欢
  • 2021-05-18
  • 2021-08-25
  • 2020-03-23
  • 2021-11-21
  • 2018-09-19
  • 2021-04-17
  • 2020-05-25
  • 1970-01-01
  • 2021-01-06
相关资源
最近更新 更多