如何在React高阶组件(HOC)中获取React Router方法?
解决React HOC中useLocation无法访问Router上下文的问题
问题描述
在React应用的高阶组件(HOC)中使用useLocation获取URL查询参数时,抛出以下错误:
Error: useLocation() may be used only in the context of a
component.
相关代码
HOC组件代码
import React, { useEffect, useState } from 'react'; import { useLocation } from 'react-router-dom'; import { getOrders } from "../../api/overview-controller"; const OrdersListHOC = (WrappedComponent) => { const orderListHOCComponent = () => { const search = useLocation().search; const limit = new URLSearchParams(search).get('limit') || 20; const [orders, setOrders] = useState([]); const [customerNumber, setCustomerNumber] = useState(""); const [subcontractor, setSubcontractor] = useState(""); useEffect (() => { fetchOrders() }, []); const fetchOrders = async() => { const searchFilter = { customerNumber, subcontractor, limit } const orders = await getOrders(searchFilter); setOrders(orders); } return ( <div> <WrappedComponent orders={orders}/> </div> ); } return orderListHOCComponent; }; export default OrdersListHOC;
订单列表组件代码
const OrdersList = ({ orders }: props) => { return (<> {orders.map((order) => { return (<React.Fragment key={order.order.id}> <Grid container justifyContent={"center"} spacing={2}> <Grid item> <Typography variant='subtitle1' mb={1/2}>Order number:</Typography> <Typography variant='subtitle1' mb={1/2}>Customer name:</Typography> </Grid> <Grid item> <Typography variant='h6'>{order.order.kind}{order.order.location.countryCode}{moment(order.order.orderDate, "YYYY-MM-DD").format("YY")}/{order.order.id}</Typography> <Typography variant='h6'>{order.order.customerNumber.name}</Typography> </Grid> </Grid> <Divider light={false}/> </React.Fragment>)})} </>); } export default OrderListHOC(OrdersList);
解决方案
方案1:确保组件处于Router上下文范围内
useLocation是React Router的钩子,必须在<Router>(如BrowserRouter)组件的包裹下才能正常使用。检查你的应用路由配置,确保被HOC包装后的OrdersList组件是在Router内部渲染的。
示例路由配置:
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; import OrdersList from './path/to/OrdersList'; function App() { return ( <Router> <Routes> <Route path="/orders" element={<OrdersList />} /> </Routes> </Router> ); }
方案2:拆分路由逻辑与HOC,提升复用性
如果需要让HOC在非路由场景下也能复用,可以将获取查询参数的逻辑从HOC中移出,放到处于Router上下文内的容器组件中,再将参数传递给HOC包装后的组件。
修改后的HOC
import React, { useEffect, useState } from 'react'; import { getOrders } from "../../api/overview-controller"; const OrdersListHOC = (WrappedComponent) => { const orderListHOCComponent = ({ limit = 20 }) => { const [orders, setOrders] = useState([]); const [customerNumber, setCustomerNumber] = useState(""); const [subcontractor, setSubcontractor] = useState(""); useEffect(() => { fetchOrders(); }, []); const fetchOrders = async () => { const searchFilter = { customerNumber, subcontractor, limit }; const orders = await getOrders(searchFilter); setOrders(orders); }; return ( <div> <WrappedComponent orders={orders} /> </div> ); }; return orderListHOCComponent; }; export default OrdersListHOC;
新增容器组件处理路由逻辑
import { useLocation } from 'react-router-dom'; import OrdersList from './OrdersList'; import OrdersListHOC from './OrdersListHOC'; const OrdersListContainer = () => { const search = useLocation().search; const limit = new URLSearchParams(search).get('limit') || 20; const WrappedOrdersList = OrdersListHOC(OrdersList); return <WrappedOrdersList limit={limit} />; }; export default OrdersListContainer;
之后在路由配置中使用这个容器组件即可:
<Route path="/orders" element={<OrdersListContainer />} />
内容的提问来源于stack exchange,提问作者Profer
相关产品推荐
相关产品推荐

