I have a map of an objects. Each object is an item in a list. When I click on a concrete item it moves me to a specific route with that item's id. How to properly manage that concrete item's props inside new route?
Is this the way to go or there is better way?
export const Router = (): ReactElement => {
const [itemDetails, setItemDetails] = useState<Item>();
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Root />}>
<Route
index
element={<ItemList setItemDetails={setItemDetails} />}
/>
<Route
path="/item/:itemId"
element={<ItemDetails itemDetails={itemDetails} />}
/>
</Route>
</Routes>
</BrowserRouter>
);
};
So basically what I'm doing here is I'm passing state setter function to a list where my mapped items are stored so when I click on a concrete one I save its props to that function.
Then I just pass updated state to a new route where details of a concrete item should be displayed.
CodePudding user response:
If you are asking if there's a better way than pushing some value from ItemList
up to the parent state to be passed down to ItemDetails
, then sure, a more React/react-router-dom
way would be to hoist the items array from the ItemList
component up to this parent component and pass the data down to children routes as props or via a context.
Example using props
export const Router = (): ReactElement => {
const [items, setItems] = useState<Array<Item>>([]);
... logic to populate items state ...
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Root />}>
<Route index element={<ItemList items={items} />} />
<Route path="/item/:itemId" element={<ItemDetails items={items} />} />
</Route>
</Routes>
</BrowserRouter>
);
};
ItemDetails
const ItemDetails = ({ items }) => {
const { itemId } = useParams();
const item = items.find(item => String(item.id) === itemId);
if (!item) {
return <div>No matching item found.</div>;
}
return (
... render item out to JSX
);
};
Example using Outlet context
export const Router = (): ReactElement => {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Root />}>
<Route index element={<ItemList />} />
<Route path="/item/:itemId" element={<ItemDetails />} />
</Route>
</Routes>
</BrowserRouter>
);
};
Root
const Root = () => {
const [items, setItems] = useState<Array<Item>>([]);
... logic to populate items state ...
return (
...
<Outlet context={{ items }} />
...
);
};
ItemList
const ItemList = () => {
const { items } = useOutletContext();
return (
... map items to JSX
);
};
ItemDetails
const ItemDetails = () => {
const { items } = useOutletContext();
const { itemId } = useParams();
const item = items.find(item => String(item.id) === itemId);
if (!item) {
return <div>No matching item found.</div>;
}
return (
... render item out to JSX
);
};