我正在使用 React-Router V6,但在实现加载器时遇到问题。我需要通过上下文文件中的函数发出页面请求。但是,路由器是在 main.js 中定义的,我无法访问那里的上下文。
main.js
import ReactDOM from 'react-dom/client';
import { Navigate, RouterProvider, createBrowserRouter } from 'react-router-dom';
import App from './App.jsx';
import PetShopProvider from './context/PetShopContext.jsx';
import './index.css';
import { ErrorPage, PetInfoPage, PetsPage } from './pages/index.jsx';
import PetInfoErrorPage from './pages/ErrorPage/PetInfoErrorPage.js';
const router = createBrowserRouter([
{
path: '/',
element: <App />,
errorElement: <ErrorPage />,
children: [
{
path: '/',
element: <Navigate to="/pets" />,
},
{
path: '/pets',
element: <PetsPage />,
},
{
path: 'pets/:id',
element: <PetInfoPage />,
errorElement: <PetInfoErrorPage />,
// loader:
},
],
},
]);
ReactDOM.createRoot(document.getElementById('root') as Element).render(
// <React.StrictMode>
<PetShopProvider>
<RouterProvider router={router} />
</PetShopProvider>,
// </React.StrictMode>
);
上下文文件
import ...
export const PetShopContext = React.createContext<DataContextType | null>(null);
const PetShopProvider = ({ children }: ContextProps) => {
const [data, setData] = React.useState<DataType[]>([]);
const firestoreRef = collection(firestore, 'pets_data');
const getData = async (sortBy?: string) => {
// REVIEW:
let sortData: any;
switch (sortBy) {
case 'Z-A':
sortData = await getDocs(query(firestoreRef, orderBy('name', 'desc')));
break;
case 'Tipo':
sortData = await getDocs(query(firestoreRef, orderBy('type', 'asc'), orderBy('name', 'asc')));
break;
case 'Porte':
sortData = await getDocs(
query(firestoreRef, orderBy('type', 'asc'), orderBy('size', 'asc'), orderBy('name', 'asc')),
);
break;
default:
sortData = await getDocs(query(firestoreRef, orderBy('name', 'asc')));
break;
}
const finalData = sortData.docs.map((doc: { data: () => DataType; id: string }) => ({
...doc.data(),
id: doc.id,
}));
setData(finalData);
};
//TODO: Try Catch !
const getPet = async (petID: string) => {
const docRef = doc(firestore, 'pets_data', petID);
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
return { ...docSnap.data(), id: docSnap.id };
} else {
throw Error;
}
};
return (
<PetShopContext.Provider
value={{
data,
setData,
getData,
}}
>
{children}
</PetShopContext.Provider>
);
};
export default PetShopProvider;
宠物信息页面
import ...
const PetInfoPage = () => {
const navigate = useNavigate();
const { id } = useParams<PetInfoParams>();
const { getPet, deleteService } = React.useContext(PetShopContext) as DataContextType;
const [currentPet, setCurrentPet] = React.useState<DataType | undefined>(undefined);
const [currentPetService, setCurrentPetService] = React.useState<ServiceDataType | undefined>(undefined);
const [formModal, setFormModal] = React.useState<boolean>(false);
const [alertModal, setAlertModal] = React.useState<boolean>(false);
useEffect(() => {
setTimeout(() => {
const fetchPetData = async () => {
// REVIEW:
const petData: any = await getPet(id!);
console.log(petData);
setCurrentPet(petData);
};
fetchPetData();
}, 500);
}, []);
...
};
export default PetInfoPage;
如何使用
getPet
(PetInfo
页面)函数作为加载程序?
我需要根据加载结果来实现errorElement
。
创建一个根组件,可以访问提供的
PetShopContext
上下文并将上下文传递给任何路由加载器。
示例:
const AppRoot = () => {
const petShopContext = React.useContext(PetShopContext) as DataContextType;
const router = createBrowserRouter([
{
path: '/',
element: <App />,
errorElement: <ErrorPage />,
children: [
{
path: '/',
element: <Navigate to="/pets" />,
},
{
path: '/pets',
element: <PetsPage />,
},
{
path: 'pets/:id',
element: <PetInfoPage />,
errorElement: <PetInfoErrorPage />,
loader: petInfoLoader(petShopContext), // <-- pass context
},
],
},
]);
return <RouterProvider router={router} />;
};
ReactDOM.createRoot(document.getElementById('root') as Element).render(
<React.StrictMode>
<PetShopProvider>
<AppRoot />
</PetShopProvider>,
</React.StrictMode>
);
petInfoLoader
应该是一个柯里化函数,它接收传递的 PetShopContext
上下文值并返回加载器函数。
示例:
const petInfoLoader = (petShopContext: DataContextType) => {
return ({ params, request }) => {
const { id } = params as PetInfoParams;
const { getPet } = petShopContext;
return getPet(id!);
};
};