【问题标题】:React problem with router before fetching the user在获取用户之前对路由器的问题做出反应
【发布时间】:2021-06-25 01:30:33
【问题描述】:

我有 MERN 应用程序,它使用带有 jwt 的仅 http cookie 作为身份验证。我在 React 中创建了一个提供程序来保存用户信息。前端也有受保护的路线。在后端,如果存在 cookie,我有一个返回当前用户的路由,否则我将用户设置为 null。当应用程序启动、刷新或用户更改时,我会进行此调用。一切正常。

当我刷新页面或使用 url 栏手动导航到某个页面时出现问题。因为在这两种情况下,应用程序都会在很短的时间内刷新用户,直到获取完成为止。结果,我总是被重定向到主页,而不是我刷新或输入的页面。我尝试设置“正在加载”状态,但它仅适用于 App 组件。

示例:我在“/details/1234”上单击刷新,然后被发送回“/”。

有没有办法解决这个问题?也许路由器中的一些更改或强制 React 在获取完成之前不做任何事情?提前致谢。

这是我的提供商的代码:

import { createContext, useEffect, useState } from 'react';

export const AuthContext = createContext();

function AuthContextProvider(props) {

    const [user, setUser] = useState(null);
    const [loading, setLoading] = useState(true);

    useEffect(() => {
        async function initialUser() {
            try {
                const response = await fetch(`/api/users/profile`, {
                    headers: {
                        "Content-Type": "application/json"
                    },
                    method: "GET",
                    credentials: 'include'
                });
                setLoading(false);
                const userData = await response.json();
                return userData.message ? setUser(null) : setUser(userData)
            } catch (error) {
                console.log(error);
            }
        }
        if (!user) {
            initialUser();
        }
    }, [user]);

    return (
        <AuthContext.Provider value={{ user, loading, setUser }}>
            {props.children}
        </AuthContext.Provider>
    )
}

export default AuthContextProvider

这是应用程序组件的代码。 App Component 由 Provider 和 Router 封装在 index.js 中

import { useContext } from 'react';
import { Switch, Route, Redirect } from 'react-router-dom';
import './App.css';
import { AuthContext } from './context/AuthContext';
import Navigation from './components/Navigation/Navigation';
import Footer from './components/Footer/Footer';
import Homescreen from './components/HomeScreen/HomeScreen';
import LandingScreen from './components/LandingScreen/LandingScreen';
import SignScreen from './components/SignScreen/SignScreen';
import Search from './components/Search/Search';
import Genres from './components/Genres/Genres';
import Details from './components/Details/Details';
import Watch from './components/Watch/Watch';
import Profile from './components/Profile/Profile';


function App() {

  const { user, loading } = useContext(AuthContext);

  return (
    !loading
      ? <div className="App">
        <Navigation user={user} />
        <Switch>
          <Route exact path="/" render={() => (!user ? <LandingScreen /> : <Homescreen />)} />
          <Route path="/sign-in" render={() => (!user ? <SignScreen /> : <Redirect to="/" />)} />
          <Route path="/sign-up" render={() => (!user ? <SignScreen /> : <Redirect to="/" />)} />
          <Route path="/profile" render={() => (!user ? <Redirect to="/sign-in" /> : <Profile />)} />
          <Route path="/search" render={() => (!user ? <Redirect to="/sign-in" /> : <Search />)} />
          <Route path="/movies/:genre" render={() => (!user ? <Redirect to="/sign-in" /> : <Genres />)} />
          <Route path="/details/:id" render={() => (!user ? <Redirect to="/sign-in" /> : <Details />)} />
          <Route path="/watch/:id" render={() => (!user ? <Redirect to="/sign-in" /> : <Watch />)} />
        </Switch>
        <Footer />
      </div>
      : null
  );
}

export default App;

【问题讨论】:

  • 你可以实际上使用那个加载状态。而且我建议创建一个“经过身份验证的路由”组件,这样你就不会重复自己。
  • 实际使用它是什么意思?我试过 " !loading ? (!user ? : ) : null)} />" 但结果相同。
  • 哦,开枪,对,你正在使用它,但更进一步。您在更新AuthContextProvider 中的用户状态之前设置了loading false。

标签: javascript node.js reactjs express react-router-dom


【解决方案1】:

您正在将loading 状态更新为假更新user 状态之前。您应该先更新用户数据然后更新加载状态。当您更新loading 状态之前时,异步 JSON 响应处理之间将至少有 1 个渲染周期,从而允许路由器以未确定的user 状态渲染路由。我建议使用try/catchfinally 块,这样无论如何,当获取处理完成时,加载状态都会更新。

function AuthContextProvider(props) {
    const [user, setUser] = useState(null);
    const [loading, setLoading] = useState(true);

    useEffect(() => {
        async function initialUser() {
            try {
                const response = await fetch(`/api/users/profile`, {
                    headers: {
                        "Content-Type": "application/json"
                    },
                    method: "GET",
                    credentials: 'include'
                });
                
                const userData = await response.json();
                userData.message ? setUser(null) : setUser(userData)
            } catch (error) {
                console.log(error);
            } finally {
                setLoading(false);
            }
        }
        if (!user) {
            initialUser();
        }
    }, [user]);

    return (
        <AuthContext.Provider value={{ user, loading, setUser }}>
            {props.children}
        </AuthContext.Provider>
    )
}

【讨论】:

  • 我测试了它,是的,它确实完全解决了问题!谢谢:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-12-05
  • 1970-01-01
  • 2022-06-28
  • 2017-03-24
  • 2019-02-01
  • 2021-03-26
  • 1970-01-01
相关资源
最近更新 更多