反应私人路线的麻烦
Trouble with react private routes
我正在尝试创建受保护的路线。我有一个反应上下文 returns true or false
如果用户是否登录。
问题是,即使我通过了身份验证,我仍然无法访问仪表板路由(即使我已登录,它也会重定向到登录)。我认为这是因为我向我的服务器发送了一个 api 请求以检查用户是否已通过身份验证,并且当时上下文值为 undefined
我试图通过在渲染路由之前检查上下文是否未定义来解决这个问题,但它仍然不起作用。
App.js
const ctx = useContext(userContext);
console.log(ctx.authed); // return true or false
return (
<div className='App'>
<Router>
<Switch>
<Route path='/' exact component={HomePage}></Route>
<Route exact path='/auth/register' component={Register}></Route>
<Route exact path='/auth/login' component={Login}></Route>
{!ctx.loading ? (
<ProtectedRoute
path='/dashboard'
isAuth={ctx.authed}
exact
component={Dashboard}
/>
) : null}
</Switch>
</Router>
</div>
);
ProtectedRoute.js
function ProtectedRoute({ isAuth, component: Component, ...rest }) {
return (
<Route
{...rest}
render={(props) => {
if (isAuth) {
return <Component />;
} else {
return (
<Redirect to={{ pathname: '/login',
state: { from: props.location } }} />
);
}
}}
/>
);
}
我的上下文如下:
export const userContext = createContext({});
export default function Context(props) {
const [authed, setAuthed] = useState(undefined);
const [loading, setLoading] = useState(false);
const fetchData = async () => {
setLoading(true);
await axios({
method: 'GET',
withCredentials: true,
credentials: 'include',
url: '/checkAuthentication',
}).then((res) => {
setAuthed(res.data.authenticated);
setLoading(false);
});
};
useEffect(() => {
fetchData();
}, []);
return (
<userContext.Provider value={{ loading, authed }}>
{props.children}
</userContext.Provider>
);
}
我已经坚持了一段时间,如果有任何帮助,我将不胜感激。谢谢!
您可以使用 useEffect
钩子来查明 React 何时更改了您的 authed
变量。当它发生时,您可以检查用户是否已登录。如果没有,您可以使用 history.push('/login')
。您可以从 react-router-dom
的 useHistory
钩子中得到 history
。在您的登录页面中,您可以使用上下文的加载变量来显示任何加载组件。
使用这种方法,您不需要使用难以管理和降低代码可读性的冗余组件。
你的代码的问题是组件挂载时context的loading
变量总是false,此时authed
的值为undefined
。这就是为什么 <ProtectedRoute />
总是呈现并将您重定向到登录页面。
@Alyks 解决方案帮助了我。除了添加 useEffect 块外,没有任何变化。
const ctx = useContext(myContext);
const [isAuth, setIsAuth] = useState(ctx.authed);
useEffect(() => { //
if (ctx.authed) { //
setIsAuth(ctx.authed); <-- added this
} //
}, [ctx.authed]); //
return (
<div className='App'>
<Router>
<a href='/dashboard'>Dashboard</a>
<a href='/auth/login'>Login</a>
<Switch>
<Route path='/' exact component={HomePage}></Route>
<Route exact path='/auth/register' component={Register}></Route>
<Route exact path='/auth/login' component={Login}></Route>
{!ctx.loading ? (
<ProtectedRoute
path='/dashboard'
isAuth={isAuth}
exact
component={Dashboard}
/>
) : null}
</Switch>
</Router>
</div>
);
我正在尝试创建受保护的路线。我有一个反应上下文 returns true or false
如果用户是否登录。
问题是,即使我通过了身份验证,我仍然无法访问仪表板路由(即使我已登录,它也会重定向到登录)。我认为这是因为我向我的服务器发送了一个 api 请求以检查用户是否已通过身份验证,并且当时上下文值为 undefined
我试图通过在渲染路由之前检查上下文是否未定义来解决这个问题,但它仍然不起作用。
App.js
const ctx = useContext(userContext);
console.log(ctx.authed); // return true or false
return (
<div className='App'>
<Router>
<Switch>
<Route path='/' exact component={HomePage}></Route>
<Route exact path='/auth/register' component={Register}></Route>
<Route exact path='/auth/login' component={Login}></Route>
{!ctx.loading ? (
<ProtectedRoute
path='/dashboard'
isAuth={ctx.authed}
exact
component={Dashboard}
/>
) : null}
</Switch>
</Router>
</div>
);
ProtectedRoute.js
function ProtectedRoute({ isAuth, component: Component, ...rest }) {
return (
<Route
{...rest}
render={(props) => {
if (isAuth) {
return <Component />;
} else {
return (
<Redirect to={{ pathname: '/login',
state: { from: props.location } }} />
);
}
}}
/>
);
}
我的上下文如下:
export const userContext = createContext({});
export default function Context(props) {
const [authed, setAuthed] = useState(undefined);
const [loading, setLoading] = useState(false);
const fetchData = async () => {
setLoading(true);
await axios({
method: 'GET',
withCredentials: true,
credentials: 'include',
url: '/checkAuthentication',
}).then((res) => {
setAuthed(res.data.authenticated);
setLoading(false);
});
};
useEffect(() => {
fetchData();
}, []);
return (
<userContext.Provider value={{ loading, authed }}>
{props.children}
</userContext.Provider>
);
}
我已经坚持了一段时间,如果有任何帮助,我将不胜感激。谢谢!
您可以使用 useEffect
钩子来查明 React 何时更改了您的 authed
变量。当它发生时,您可以检查用户是否已登录。如果没有,您可以使用 history.push('/login')
。您可以从 react-router-dom
的 useHistory
钩子中得到 history
。在您的登录页面中,您可以使用上下文的加载变量来显示任何加载组件。
使用这种方法,您不需要使用难以管理和降低代码可读性的冗余组件。
你的代码的问题是组件挂载时context的loading
变量总是false,此时authed
的值为undefined
。这就是为什么 <ProtectedRoute />
总是呈现并将您重定向到登录页面。
@Alyks 解决方案帮助了我。除了添加 useEffect 块外,没有任何变化。
const ctx = useContext(myContext);
const [isAuth, setIsAuth] = useState(ctx.authed);
useEffect(() => { //
if (ctx.authed) { //
setIsAuth(ctx.authed); <-- added this
} //
}, [ctx.authed]); //
return (
<div className='App'>
<Router>
<a href='/dashboard'>Dashboard</a>
<a href='/auth/login'>Login</a>
<Switch>
<Route path='/' exact component={HomePage}></Route>
<Route exact path='/auth/register' component={Register}></Route>
<Route exact path='/auth/login' component={Login}></Route>
{!ctx.loading ? (
<ProtectedRoute
path='/dashboard'
isAuth={isAuth}
exact
component={Dashboard}
/>
) : null}
</Switch>
</Router>
</div>
);