[英]React app keeps refreshing when changing i18next language in combination with authenticated routes
我有一個帶有身份驗證(基於cookie)的react-app,帶有登錄路由和配置文件路由。 配置文件路由正在獲取配置文件數據並將數據放入表單中。 其中一個領域是語言領域。 我正在使用useEffect
掛鈎來觀察語言屬性並使用i18n.changeLanguage()
來更改語言。
出於某種原因,當我添加此代碼時,頁面會不斷刷新。 它必須是此代碼與我正在使用的代碼的組合,用於檢查用戶是否已通過身份驗證以訪問路由。 當我注釋掉 protectedRoute function 或 useEffect 鈎子時,它正在工作,但我顯然需要兩者。
protectedRoute function 和 authContext 的小故障。
路由包裝在 AuthProvider 中
const App = () => {
return (
<BrowserRouter>
<AuthProvider>
<Router />
</AuthProvider>
</BrowserRouter>
);
};
在 AuthProvider 中,我有一個user
和isAuthenticated
state。 兩者都以null
的值開頭。 在掛載帶有或不帶有 cookie 的調用時,會在后端完成以獲取用戶信息。 如果返回帶有 id 的用戶 object,則isAuthenticated
state 設置為 true。
const AuthProvider = ({ children }) => {
const [isAuthenticated, setIsAuthenticated] = useState(null);
const [user, setUser] = useState(null);
useEffect(() => {
getUserInfo();
}, []);
const getUserInfo = async () => {
try {
const { data } = await authService.me();
setIsAuthenticated(true);
setUser(data);
} catch (error) {
setIsAuthenticated(false);
setUser({});
}
};
const setAuthInfo = (user) => {
setIsAuthenticated(!!(user && user.id));
setUser(user);
};
...
只要 isAuthenticated 是null
,就會呈現加載 state 而不是路由。
if (authContext.isAuthenticated === null) {
return (
<div>
<span>Loading...</span>
</div>
);
}
const ProtectedRoutes = () => {
return authContext.isAuthenticated ? (
<Outlet />
) : (
<Navigate to="/login" replace />
);
};
return (
<Routes>
<Route path="/login" element={<Login />} />
<Route element={<ProtectedRoutes />}>
<Route path="/" element={<Navigate to="/profile" replace />} />
<Route path="/profile" element={<ProfileOverview />} />
</Route>
</Routes>
);
當isAuthenticated
state 為 true 時,可以訪問配置文件頁面。 在配置文件頁面內,獲取用戶配置文件信息,並將重置設置為 state 表格。 這將觸發 useEffect 鈎子監視formData.language
屬性,該屬性會將語言設置為用戶的語言。 這會導致持續刷新,我找不到原因或我做錯了什么。
const Profile = () => {
const { i18n } = useTranslation();
const { formData, reset, handleSubmit, handleChange } = useForm({});
useEffect(() => {
console.log("Get profile data");
getProfileInfo();
}, []);
useEffect(() => {
i18n.changeLanguage(formData.language);
}, [formData.language]);
const getProfileInfo = async () => {
const { data } = await profileService.getProfileInfo();
reset(data);
};
const submit = (values) => {
console.log("submit");
};
...
Codesandbox 演示在這里。 我在個人資料頁面的 useEffect 中放置了一個 console.log,因此您可以看到它不斷刷新。 無需憑據即可登錄。 所有獲取都是通過 setTimeout 來完成的,以偽造真實的調用。
取自Codesandbox 演示並在Profile.js
中修改。 這個想法是阻止對i18n.changeLanguage
的其他請求,直到前一個請求完成並且語言真正更新。
// Use a state variable to verify we aren't already loading
const [isLoadingLanguage, setLoadingLanguage] = useState(false);
useEffect(() => {
// Verify we aren't loading and are actually changing the language
if (!isLoadingLanguage && formData.language !== language) {
const load = async () => {
// Set the state as loading so we don't perform additional requests
setLoadingLanguage(true);
// Since this method returns a promise, and useEffect does not allow async/await easily,
// make and call an async method so we can await changeLanguage
await i18n.changeLanguage(formData.language);
// Set the state as not loading so we can perform additional requests
setLoadingLanguage(false);
};
load();
}
}, [i18n, formData.language]);
我要注意,要讓它在沙箱中工作需要刪除i18n.changeLanguage
的行,這樣永久渲染就不會繼續提交請求。 然后,添加上面的useEffect
加載表單並提供單個提交。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.