如何让React路由器加载程序等待axios实例初始化?

问题描述 投票:0回答:1

我有一个 axios 实例,需要配置它才能开始进行正常的 API 调用。我需要设置授权标头并放置 1 个拦截器,该拦截器将在每个 401 请求上刷新 JWT 令牌。因为我使用的是钩子,所以我将其制作成一个单独的组件,然后将其嵌套在我的 App.tsx 中。

我正在使用react-router-dom 中支持“加载器”功能的数据路由器之一。问题是,当我刷新路由页面(假设“/profile”)时,它首先调用加载器函数,然后才调用所有 useEffect 实例。它显然会导致 401 错误,即使在 Axios 组件渲染时用户已在 useAuth() 挂钩中设置。

那家伙也有和我类似的问题,但我在评论中没有找到合适的答案
创建路由器时,React Router Dom V6 加载程序会触发

正如他所说,我什至可以从我的 App 组件返回语句中删除 ,它仍然会在 useEffect 之前调用 loader。即使此后不会渲染该路由器的任何组件。

这是视频,如果它能让您更好地理解这个问题:
https://youtu.be/MoV_924owTU

任何帮助都可以!

AxiosSettings.tsx:

import axios from 'axios';
import useAuth from '../hooks/useAuth';
import {useEffect} from 'react';

const api = axios.create({
    baseURL: 'http://127.0.0.1:8000/api/',
    headers: {
        "Content-Type": "application/json",
    },
})

export function AxiosSettings({children}: { children: ReactNode }) {
    // Using this only because I need to call useAuth() hook in order to get user
    const {user, login} = useAuth()

    useEffect(() => {
        console.log('effect 1')
        if (user) {
            api.defaults.headers.common["Authorization"] = `Bearer ${user.accessToken}`
        } else {
            delete api.defaults.headers.common["Authorization"]
        }
    }, [user])

    useEffect(() => {
        console.log('effect 2')
        const interceptor = api.interceptors.response.use(...)
        return api.interceptors.response.eject(interceptor)
    }, []);

    return children;
}

export default api

我的应用程序组件的结构如下:

const router = createBrowserRouter(createRoutesFromElements(
    <Route element={<RootLayout/>}>
        <Route index element={<Home/>}/>

        <Route path="register" element={<Signup/>}/>
        <Route path="login" element={<Login/>}/>
        <Route path="about"/>

        <Route element={<RequireAuth/>}>
            <Route path="profile" element={<ProfileLayout/>} loader={ProfileLoader}>
                <Route index element={<ProfileIndex/>} loader={PrizesLoader}/>
                <Route path="history"/>
                <Route path="invitations"/>
            </Route>
        </Route>

        <Route path="admin" element={<RequireAdmin/>}>
            <Route index element={<AdminPage/>}/>
            <Route path="game/:hash" element={<Game/>}/>
        </Route>
    </Route>
))

function App() {
    const [user, setUser] = useState<User | null>(() => {
        return SessionStorageUserService.get();
    })

    return (
        <AuthContext.Provider value={{user, setUser}}>
            <AxiosSettings>
                <RouterProvider router={router} />
            </AxiosSettings>
        </AuthContext.Provider>
    )
}
reactjs axios react-router loader
1个回答
0
投票

仅当 axios 效果已运行并设置标头并附加响应拦截器时,

AxiosSettings
才能有条件地渲染其
children

export function AxiosSettings({ children }: { children: ReactNode }) {
  const [isLoaded, setIsLoaded] = useState(false);

  const { user, login } = useAuth();

  useEffect(() => {
    console.log('effect 1');
    if (user) {
      api.defaults.headers.common["Authorization"] = `Bearer ${user.accessToken}`;
    } else {
      delete api.defaults.headers.common["Authorization"];
    }
  }, [user]);

  useEffect(() => {
    console.log('effect 2');
    const interceptor = api.interceptors.response.use(...);

    setIsLoaded(true);
    return api.interceptors.response.eject(interceptor);
  }, []);

  return isLoaded
    ? children
    : null; // <-- or loading indicator/spinner/etc
}

RouterProvider
将有条件地渲染,并且它和用户所在的路线将不会被渲染,直到至少配置了 axios
api
实例后的第二个渲染周期。

© www.soinside.com 2019 - 2024. All rights reserved.