[英]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.