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 componentWillReceivePropscomponentWillReceiveProps(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 React Router does not update component if url parameter changes
When a URL's path changes, the current Component is unmounted and the new component pointed by the new URL is mounted. However, when a URL's param changes, since the old and new URL path points to the same component, no unmount-remount takes place; only the already mounted component receives new props. One can make use of these new props to fetch new data and render updated UI.
Suppose your param id is parameter
.
With hooks:
useEffect(() => {
// ... write code to get new data using new prop, also update your state
}, [props.match.params.parameter]);With class components:
componentDidUpdate(prevProps){
if(this.props.match.params.parameter!== prevProps.match.params.parameter){
// ... write code to get new data using new prop, also update your state
}
}Use KEY:
Another approach could be to use the unique key prop. Passing a new key will force a
component to remount.<Route path="/teams/:parameter" render={(props) => (
<Team key={props.match.params.parameter} {...props} />
)} />
Why React-router doesn't re-render the page and doesn't update the data when the url changes?
If// Details.jsx description page
<div className="description">
<p>BLa bla bla</p>
<Link to={`/${eleId}`}>Related</Link>
<div>
Details
component is linking to itself, i.e. the route rendering it, this means the route path is already matched and rendering Details
. Details
may need to "listen" for changes on the eleId
route match param. Use the useParams
React hook to access the eleId
param and an useEffect
hook with eleId
as a dependency to run any side-effect necessary when the param updates.Example:
import { useParams } from 'react-router-dom';
...
const Details = () => {
const { eleId } = useParams();
const [data] = useData(`alpha/${eleId}`);
...
useEffect(() => {
// Business logic to run when eleId updates
}, [eleId]);
...
For the useData
hook, move the url
declaration into the useEffect
hook and add the param
argument as a dependency for the effect. When the param changes this will retrigger the useEffect
and refetch data.const useData = (param = 'all') => {
const [data, setData] = useState([]);
const [error, setError] = useState(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const url = 'https://restcountries.com/v2/' + param;
const fetchAPI = async () => {
setIsLoading(true);
try {
const response = await fetch(url);
const json = await response.json();
setData(json);
setError(false);
} catch(err) {
setError(err.message);
setData(null);
console.log(err);
}
setIsLoading(false);
};
fetchAPI();
}, [param]);
return [data, error, isLoading];
}
Component does not remount when route parameters change
If the link is directing to the same route with just a different param, it's not remounting, but instead receiving new props. So, you could use the componentWillReceiveProps(newProps)
function and look for newProps.params.projectId
.
If you're trying to load data, I would recommend fetching the data on before the router handles the match using static methods on the component. Check out this example. React Router Mega Demo. That way, the component would load the data and automatically update when the route params change without needing to rely on componentWillReceiveProps
.
Component won't reload with new data when route parameters change
I think you're pretty close, but a mixture of misunderstanding lifecycle methods and when/how they are called is leading to some issues.
You probably should be using componentDidUpdate
. I would also avoid storing the prop in state as they will then need to be kept in sync.
componentDidUpdate(prevProps) {
if (prevProps.match.params.id !== this.props.match.params.id) {
this.setState({ user: null });
fetchUserData(this.props.match.params.id)
.then((user) => {
this.setState({ user: user });
})
}
}
Also, don't manually trigger the lifecycle methods (as mentioned in the comments) Query param not working on refresh or manual load
that's a normal behavior because your page is statically optimized
During prerendering, the router's query object will be empty since we do not have query information to provide during this phase. After hydration, Next.js will trigger an update to your application to provide the route parameters in the query object.
To be able to distinguish if the query is fully updated and ready for use, you can leverage the isReady field on next/router.You have to use
router.isReady
in a useEffect
, something like the code below:const router = useRouter();
useEffect(()=>{
if(!router.isReady) return;
// codes using router.query
}, [router.isReady]);
React router: component not updating on url search param change
As @forJ correctly pointed out, the main idea is to make the component re render once the URL
parameters change. I achieved it like so:
render() {
return (
<Switch>
<Route path="/hello" render={() => (<Hello key={this.props.location.key}/>)}></Route>
<Route path="/" component={Home}></Route>
</Switch>
);
}
this.props.location.key
changes every time the URL
changes (also if the query params change). So if you pass it as props to the component, then the component re renders on URL
param changes, even though the base URL
(the URL
without the URL
params) hasn't changed.I also had to use the withRouter
higher order component to make it work.
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Hello));
Related Topics
How Are JavaScript Arrays Represented in Physical Memory
JavaScript Getelementbyname Doesn't Work
Why Does JavaScript Getyear() Return 108
Angularjs - UI Router - Programmatically Add States
How to Getting Browser Current Locale Preference Using JavaScript
Differencebetween Native Objects and Host Objects
Dynamic Require in Requirejs, Getting "Module Name Has Not Been Loaded Yet for Context" Error
How to Create a Stopwatch Using JavaScript
Why Threre Is No Way to Download File Using Ajax Request
Remove Zero-Width Space Characters from a JavaScript String
Access Properties of the Parent with a Handlebars 'Each' Loop
JavaScript .Replace Only Replaces First Match
Pass Variables to JavaScript in Expressjs
Create Copy of Multi-Dimensional Array, Not Reference - JavaScript
JavaScript When to Use Prototypes
Converting a Buffer into a Readablestream in Node.Js