React doesn't reload component data on route param change or query change
Along with componentDidMount
, You also need to implement the componentWillReceiveProps
or use getDerivedStateFromProps
(from v16.3.0 onwards) in Products
page since the same component is re-rendered
with updated params
and not re-mounted
when you change the route params, this is because params are passed as props to the component and on props change, React components re-render and not re-mounted.
EDIT: from v16.3.0 use getDerivedStateFromProps
to set/update state based on props(no need to specify it in two different lifecyle methods)
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.match.params.product !== prevState.currentProductId){
const currentProductId = nextProps.match.params.product
const result = productlist.products.filter(obj => {
return obj.id === currentProductId;
})
return {
product: result[0],
currentId: currentProductId,
result
}
}
return null;
}
Prior v16.3.0, you would use componentWillReceiveProps
componentWillReceiveProps(nextProps) {
if (nextProps.match.params.product !== this.props.match.params.product) {
const currentProductId = nextProps.match.params.product
const result = productlist.products.filter(obj => {
return obj.id === currentProductId;
})
this.setState({
product: result[0],
currentId: currentProductId,
result
})
}
}
Working codesandbox
As Product component is already loaded it will not reload. You have to handle new product id in the below method of component
componentWillReceiveProps(nextProps) {
if(nextProps.match.params.name.product == oldProductId){
return;
}else {
//fetchnewProduct and set state to reload
}
With latest version of react(16.3.0 onwards)
static getDerivedStateFromProps(nextProps, prevState){
if(nextProps.productID !== prevState.productID){
return { productID: nextProps.productID};
}
else {
return null;
}
}
componentDidUpdate(prevProps, prevState) {
if(prevProps.productID !== this.state.productID){
//fetchnewProduct and set state to reload
}
}
Although all the above-mentioned ways will work, I don't see a point to use getDerivedStateFromProps
.
Based on React docs, "if you want to re-compute some data only when a prop changes, use a memoization helper instead".
Here, instead, I would suggest simply using componentDidUpdate
along with changing the Component
to PureComponenet
.
With reference to React docs, PureComponenet
s only rerender if at least one state or prop value changes. Change is determined by doing a shallow comparison of state and prop keys.
componentDidUpdate = (prevProps) => {
if(this.props.match.params.id !== prevProps.match.params.id ) {
// fetch the new product based and set it to the state of the component
};
};
Please note that the above only work if you change the Component to PureComponent, and obviously, you need to import it from React.
If you aren't maintaining state in your component, you can use componentDidUpdate
without the need for getDerivedStateFromProps
:
componentDidUpdate(prevProps) {
const { match: { params: { value } } } = this.props
if (prevProps.match.params.value !== value){
doSomething(this.props.match.params.value)
}
}