我正在尝试使用 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;
答案 0 :(得分:2)
我无法重现您的确切问题,但我认为您的 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>
)