I have 4 components: App, CatalogList, CatalogPreview, CatalogDetail
App
is the parent component and I have these state values:
const [catalog, setCatalog] = useState({ id: 1, name: 'Electronics' })
const [isModalOpen, setIsModalOpen] = useState(false)
CatalogList
and CatalogPreview
components receive the above state values as props along with their setter functions.
Inside CatalogList.js
:
I have a list of catalog links (electronics, furniture, ...) that when you click on one of them,
it opens up the CatalogPreview
modal. Inside the modal, there's an 'Explore' button.
When you click the 'Explore' button, it needs to do 4 things:
set the selected catalog in state (in App.js)
save selected catalog in localStorage
navigate to the detail page
close the modal window
I attempted the following in the 'Explore' button's click handler (Inside the modal):
function explore() {
props.setCatalog({...})
props.setIsModalOpen(false)
window.localStorage.setItem('catalog', JSON.stringify({...})
history.push('detail-route') // this brings up the CatalogDetail
}
Questions:
CatalogDetail
component, if I click a Delete button and make a delete API request,CatalogList
route AFTER the call is completed.Instead of storing the modal open/close state in the parent App
component it should be demoted to the child CatalogList
component that is managing the modal.
Move the persisting to localStorage to a useEffect
hook with a dependency on the catalog
state. When the state updates, persist it to localStorage.
Create a updateCatalog
callback function to accept a new value to update the catalog state with. Pass this to CatalogList
.
The explore
callback should be promoted/lifted up to the CatalogList
component. This allows CatalogPreview
to basically just render the modal. explore
still calls to update the catalog data, close the modal, and navigate.
App
function App() {
const [catalog, setCatalog] = useState({ id: 1, name: "Electronics" });
useEffect(() => {
window.localStorage.setItem("catalog", JSON.stringify(catalog));
}, [catalog]);
const updateCatalog = value => {
setCatalog( ...value... );
};
return (
<Switch>
<Route exact path="/">
<CatalogList updateCatalog={updateCatalog} />
</Route>
<Route exact path="/detail">
<CatalogDetail catalog={catalog} />
</Route>
</Switch>
);
}
CatalogList
function CatalogList(props) {
const history = useHistory();
const [isOpen, setIsOpen] = useState(false);
const catalogs = [
{ id: 1, name: "Electronics" },
{ id: 2, name: "Furniture & Appliances" },
{ id: 3, name: "Sports & Outdoors" }
];
const openPreview = () => {
setIsOpen(true);
};
function explore() {
props.updateCatalog(... some new value ...);
setIsOpen(false);
history.push("/detail");
}
return (
<div>
Available catalogs
<ul>
{catalogs.map((c, index) => (
<li key={c.id} onClick={() => openPreview(c.id)} className="link">
{c.name}
</li>
))}
</ul>
<CatalogPreview isOpen={isOpen} onExplore={explore} />
</div>
);
}
CatalogPreview
function CatalogPreview(props) {
return (
<Modal show={props.isOpen}>
<Modal.Header closeButton>
<Modal.Title>Catalog Preview</Modal.Title>
</Modal.Header>
<Modal.Footer>
<Button variant="primary" onClick={props.onExplore}>
Explore
</Button>
</Modal.Footer>
</Modal>
);
}
Use useHistory
and update the onClick
handler to navigate back to the home page.
function CatalogDetail(props) {
const history = useHistory();
return (
<div>
<p>Detail Page</p>
<button
onClick={() => {
// Make API call then navigate home
history.push("/");
}}
>
DELETE
</button>
</div>
);
}