简体   繁体   English

ReactJS 认证路由组件渲染之前 useEffect 钩子完成

[英]ReactJS authentication routing component rendering before useEffect hook completes

I'm trying to implement protected pages with Firebase authentication.我正在尝试使用 Firebase 身份验证来实现受保护的页面。 I created a typical PrivateRoute component that is supposed to only show the page if they're logged in, or redirect users to a login page if they aren't logged in.我创建了一个典型的 PrivateRoute 组件,该组件应该只在用户登录时显示该页面,或者如果用户未登录则将用户重定向到登录页面。

I stored the authentication status in a global state using a useEffect hook in App.js.我使用 App.js 中的 useEffect 挂钩将身份验证状态存储在全局 state 中。 After a lot of reading and research, I understand that the useEffect only completes after the Child component has loaded.经过大量阅读和研究,我了解到 useEffect 仅在 Child 组件加载后完成。

Having said that, I'm at a loss on how to pass authenticated from App to PrivateRoute.话虽如此,我对如何将身份验证从 App 传递到 PrivateRoute 感到茫然。 With my current code, the authenticated state only registers as true after PrivateRoute has pushed users to the login page.使用我当前的代码,经过身份验证的 state 仅在 PrivateRoute 将用户推送到登录页面后注册为 true。 Would appreciate any help.将不胜感激任何帮助。

App.js应用程序.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 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减速器.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;

I can't reproduce your exact problem but I think your PrivateRoute is wrong.我无法重现您的确切问题,但我认为您的 PrivateRoute 是错误的。 Try something like the example bellow.试试下面的例子。

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;

Use a isLoading state variable so you are not redirected before checking the firebase.auth().onAuthStateChanged.使用 isLoading state 变量,以便在检查 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>
)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在渲染组件之前运行 useEffect 钩子 - Make useEffect hook run before rendering the component 组件不会使用“useEffect”钩子在 React 中重新渲染 - Component not re-rendering in React using a 'useEffect' hook 双重渲染 useEffect reactjs - Double rendering useEffect reactjs Reactjs 路由和使用Params Hook - Reactjs Routing and useParams Hook 具有useEffect的ReactJS无法呈现每个状态 - ReactJS with useEffect not rendering each state React hook form useEffect 不会通过调用另一个组件来重新渲染功能组件 - React hook form useEffect not re-rendering functional component with call to another component 当 State 在 ReactJS 中的不同 .js 文件的组件中发生更改时,如何更新我的 useEffect 挂钩? - How to update my useEffect hook when State change happen in a different .js file's component in ReactJS? Angular2-在路由和渲染组件之前通过服务获取数组 - Angular2 - Fetch array through service before routing and rendering the component 使用 useEffect 挂钩获取数据时,React 组件不会在 URL 参数更改上重新渲染 - React component not re-rendering on URL parameter change when using useEffect hook to fetch data 在ReactJs中渲染视图之前进行组件安装以验证url参数 - Component Mounting to validate url parameter before view rendering in ReactJs
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM