我有一个基于JWT的API.它在每个响应上轮换令牌.我有一个自定义的提供程序来管理这一点.
我正在try 弄清楚如何在此设置下使用REACT RouteV6.4数据路由.具体地说,我希望使用loader
/action
函数来获取数据,但这些函数不支持useContext
,我不确定如何传递它.
我希望dashboardLoader
用当前令牌集作为标头来调用API,AuthContext
为我管理这些标头.
目标是让loader
函数获取一些数据以显示在仪表板上,并使用来自AuthProvider
的get()
调用.
我目前的替代方案是只在Dashboard
组件内完成,但希望了解如何使用加载器来实现这一点.
相关文件:
// App.js
import "./App.css";
import { createBrowserRouter } from "react-router-dom";
import "./App.css";
import Dashboard, { loader as dashboardLoader } from "./dashboard";
import AuthProvider from "./AuthProvider";
import axios from "axios";
function newApiClient() {
return axios.create({
baseURL: "http://localhost:3000",
headers: {
"Content-Type": "application/json",
},
});
}
const api = newApiClient();
export const router = createBrowserRouter([
{
path: "/",
element: (<h1>Welcome</h1>),
},
{
path: "/dashboard",
element: (
<AuthProvider apiClient={api}>
<Dashboard />
</AuthProvider>
),
loader: dashboardLoader,
},
]);
// AuthProvider
import { createContext, useState } from "react";
const AuthContext = createContext({
login: (email, password) => {},
isLoggedIn: () => {},
get: async () => {},
post: async () => {},
});
export function AuthProvider(props) {
const [authData, setAuthData] = useState({
client: props.apiClient,
accessToken: "",
});
async function login(email, password, callback) {
try {
const reqData = { email: email, password: password };
await post("/auth/sign_in", reqData);
callback();
} catch (e) {
console.error(e);
throw e;
}
}
function isLoggedIn() {
return authData.accessToken === "";
}
async function updateTokens(headers) {
setAuthData((prev) => {
return {
...prev,
accessToken: headers["access-token"],
};
});
}
async function get(path) {
try {
const response = await authData.client.get(path, {
headers: { "access-token": authData.accessToken },
});
await updateTokens(response.headers);
return response;
} catch (error) {
console.error(error);
throw error;
}
}
async function post(path, data) {
try {
const response = await authData.client.post(path, data, {
headers: { "access-token": authData.accessToken },
});
await updateTokens(response.headers);
return response.data;
} catch (error) {
// TODO
console.error(error);
throw error;
}
}
const context = {
login: login,
isLoggedIn: isLoggedIn,
get: get,
post: post,
};
return (
<AuthContext.Provider value={context}>
{props.children}
</AuthContext.Provider>
);
}
// Dashboard
import { useContext } from "react";
import { Navigate } from "react-router-dom";
import AuthContext from "./AuthProvider";
export function loader() {
// TODO use auth context to call the API
// For example:
// const response = await auth.get("/my-data");
// return response.data;
}
export default function Dashboard() {
const auth = useContext(AuthContext);
if (!auth.isLoggedIn()) {
return <Navigate to="/" replace />;
}
return <h1>Dashboard Stuff</h1>;
}