Reputation: 893
The Router
configuration looks like following
App.js
<Router>
<Switch>
<Route exact path="/" render={() => <Home />} />
<Route exact path="/products/:productId" component={ ProductDetail } />
<Redirect to="/" />
</Switch>
</Router>
Here is how ProductDetail
component looks like
ProductDetail.js
export const ProductDetail = ({ match }) => {
const productId = match.params.productId;
useEffect(() => {
dispatch(fetchProductById(productId));
}, [productId, dispatch]);
const product = useSelector((state) => selectProductById(state, productId));
return(<.....>)
}
Now when I navigate from Home
to ProductDetail
then everything works fine. However if I try to hit url http://localhost:3000/products/someId
directly, the component doesn't render and useEffect
hook doesn't get called.
I have read the Router
documentation, and it says
When you use component (instead of render or children, below) the router uses React.createElement to create a new React element from the given component.
Shouldn't that mean the newly created component(ProductDetail
in my case) should render and hooks get called?
I am new to React
so I might be missing something fairly straightforward.
Upvotes: 0
Views: 69
Reputation: 13662
As mentioned in the comments, the product will not be in the store yet when directly navigating to the ProductDetail
component. The useEffect
hook initiates the loading of the product, but until that finishes, product
will be undefined (or null, or something else depending on your reducer). You'll need to handle this case separately.
The most simple way to handle it is to render a loading indicator of some sort, e.g.
export const ProductDetail = ({ match }) => {
const productId = match.params.productId;
useEffect(() => {
dispatch(fetchProductById(productId));
}, [productId, dispatch]);
const product = useSelector((state) => selectProductById(state, productId));
if (!product) {
return <p>Loading...</p>
}
return(<.....>)
}
Additionally, as also mentioned in the comments, hooks in general fire when a component renders. The component does not wait for an action initiated by the useEffect
hook to finish. From React's docs:
The function passed to
useEffect
will run after the render is committed to the screen.
Upvotes: 1