I have created on HOC component in my react application to reuse my code and for some purpose I need search params from the query but the react-router-dom
is not accessible inside it and throwing error.
Here is my HOC component
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;
Here is my order list component
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);
Error:
Error: useLocation() may be used only in the context of a <Router> component.
The error message isn't exactly unclear, the useLocation
hook can only be used within a routing context, e.g. a router. You just need to ensure there's a router upstream, i.e. higher in the ReactTree than any component that needs it. I'd suggest also using the useSearchParams
hook instead of constructing your own URLSearchParams
object.
import React, { useEffect, useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import { getOrders } from "../../api/overview-controller";
const withOrdersList = (WrappedComponent) => (props) => {
const [searchParams] = useSearchParams();
const limit = searchParams.get('limit') || 20;
const [orders, setOrders] = useState([]);
const [customerNumber, setCustomerNumber] = useState("");
const [subcontractor, setSubcontractor] = useState("");
useEffect (() => {
const fetchOrders = async () => {
const searchFilter = {
customerNumber,
subcontractor,
limit
}
const orders = await getOrders(searchFilter);
setOrders(orders);
}
fetchOrders();
}, []);
return <WrappedComponent {...props} orders={orders} />;
};
export default withOrdersList;
const OrdersList = ({ orders }: props) => {
return (
<>
{orders.map((order) => (
<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 withOrderList(OrdersList);
import { BrowserRouter } from 'react-router-dom';
import OrderList from '../path/to/OrderList';
...
<BrowserRouter> // <-- provide routing context to sub-Reactree
...
<div>
<OrderList /> // <-- can access routing context
</div>
...
</BrowserRouter>