如何在 React 组件中结合使用 useNavigate 和 useEffect 以在组件渲染时有条件地重定向?
How to use useNavigate in combination with useEffect in React component to conditionally redirect when component renders?
在我的“主要”组件(包含我的“路由器”和所有“路由”的组件)中,我想从我的“后端”获取当前登录的用户。
然后我要么将这个用户存储在我的全局“上下文”中(使他们可以从所有“页面”访问,允许保护某些“路由”等),如果有的话,或者我想如果当前没有用户登录,则重定向到我的“登录页面”(参见下面示例代码中的 switch
语句)。
但是,这不起作用,因为 navigate()
似乎仅当对它的调用源自 <Router>
组件时才起作用。有没有一种简单且“最佳实践”的方法来解决这个问题?非常感谢任何提示或想法!谢谢!
import React, { useState, useMemo, useEffect } from 'react';
import {
BrowserRouter as Router,
Routes,
Route,
useNavigate,
} from 'react-router-dom';
import { User, Context, UserContext } from '../lib/UserContext';
import Home from '../pages/Home';
import Test from '../pages/Test';
import Login from '../pages/Login';
import Register from '../pages/Register';
import axios from 'axios';
const StatusCodes = require('../statusCodes');
const AppRouter = () => {
const navigate = useNavigate();
const [user, setUser] = useState<User | null>(null);
const context = useMemo<Context>(
() => ({ user: user, setUser: setUser }),
[user, setUser]
);
useEffect(() => {
axios({
method: 'GET',
withCredentials: true,
url: 'http://localhost:4000/user',
}).then((res) => {
switch (res.data.code) {
case StatusCodes.UserIsLoggedIn:
console.log('A user is logged in. Context set to this user.');
context.setUser({
lastName: res.data.user.lastName,
firstName: res.data.user.firstName,
email: res.data.user.email,
role: res.data.user.role,
});
break;
case StatusCodes.NoUserIsLoggedIn:
console.log('No user is logged in. Redirect to login page.');
navigate('/login');
break;
default:
console.log('Status code not recognized. Redirect to test page.');
navigate('/test');
break;
}
});
}, []);
return (
<UserContext.Provider value={context}>
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/test" element={<Test />} />
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
</Routes>
</Router>
</UserContext.Provider>
);
};
export default AppRouter;
Is there a simple and "best-practice" way to solve this?
是的!您可以在 ReactTree 中将 Router
移至更高位置...高于您要使用 navigate
函数的组件 and 提供您要更新的上下文值。
const AppRouter = () => {
const navigate = useNavigate();
const [user, setUser] = useState<User | null>(null);
const context = useMemo<Context>(
() => ({ user: user, setUser: setUser }),
[user, setUser]
);
...
return (
<UserContext.Provider value={context}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/test" element={<Test />} />
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
</Routes>
</UserContext.Provider>
);
};
...
<Router>
<AppRouter />
</Router>
在我的“主要”组件(包含我的“路由器”和所有“路由”的组件)中,我想从我的“后端”获取当前登录的用户。
然后我要么将这个用户存储在我的全局“上下文”中(使他们可以从所有“页面”访问,允许保护某些“路由”等),如果有的话,或者我想如果当前没有用户登录,则重定向到我的“登录页面”(参见下面示例代码中的 switch
语句)。
但是,这不起作用,因为 navigate()
似乎仅当对它的调用源自 <Router>
组件时才起作用。有没有一种简单且“最佳实践”的方法来解决这个问题?非常感谢任何提示或想法!谢谢!
import React, { useState, useMemo, useEffect } from 'react';
import {
BrowserRouter as Router,
Routes,
Route,
useNavigate,
} from 'react-router-dom';
import { User, Context, UserContext } from '../lib/UserContext';
import Home from '../pages/Home';
import Test from '../pages/Test';
import Login from '../pages/Login';
import Register from '../pages/Register';
import axios from 'axios';
const StatusCodes = require('../statusCodes');
const AppRouter = () => {
const navigate = useNavigate();
const [user, setUser] = useState<User | null>(null);
const context = useMemo<Context>(
() => ({ user: user, setUser: setUser }),
[user, setUser]
);
useEffect(() => {
axios({
method: 'GET',
withCredentials: true,
url: 'http://localhost:4000/user',
}).then((res) => {
switch (res.data.code) {
case StatusCodes.UserIsLoggedIn:
console.log('A user is logged in. Context set to this user.');
context.setUser({
lastName: res.data.user.lastName,
firstName: res.data.user.firstName,
email: res.data.user.email,
role: res.data.user.role,
});
break;
case StatusCodes.NoUserIsLoggedIn:
console.log('No user is logged in. Redirect to login page.');
navigate('/login');
break;
default:
console.log('Status code not recognized. Redirect to test page.');
navigate('/test');
break;
}
});
}, []);
return (
<UserContext.Provider value={context}>
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/test" element={<Test />} />
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
</Routes>
</Router>
</UserContext.Provider>
);
};
export default AppRouter;
Is there a simple and "best-practice" way to solve this?
是的!您可以在 ReactTree 中将 Router
移至更高位置...高于您要使用 navigate
函数的组件 and 提供您要更新的上下文值。
const AppRouter = () => {
const navigate = useNavigate();
const [user, setUser] = useState<User | null>(null);
const context = useMemo<Context>(
() => ({ user: user, setUser: setUser }),
[user, setUser]
);
...
return (
<UserContext.Provider value={context}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/test" element={<Test />} />
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
</Routes>
</UserContext.Provider>
);
};
...
<Router>
<AppRouter />
</Router>