React Router v6:使用 Context API 的加载器函数

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

我正在使用 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

javascript reactjs typescript react-router react-router-dom
1个回答
0
投票

创建一个根组件,可以访问提供的

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!);
  };
};
© www.soinside.com 2019 - 2024. All rights reserved.