簡體   English   中英

React 應用程序在更改 i18next 語言並結合經過身份驗證的路由時不斷刷新

[英]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 中,我有一個userisAuthenticated 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM