Reputation: 183
import React, { Component } from 'react';
import { NavLink } from 'react-router-dom';
class Home extends Component {
constructor(props) {
super(props);
this.state = {
id: null,
newpage: '',
};
this.refresh = this.refresh.bind(this);
}
refresh() {
const geturl = new URLSearchParams(window.location.search);
const getid = urlParams.get('id');
this.setState({ id: getid });
}
componentDidMount() {
// axios commands to get navigation bar setting it newpage state
this.refresh();
}
render() {
const id = this.state.id;
const newpage = this.state.newpage.map(o => (
<NavLink to={'/Home?id=' + o.id} onClick={this.refresh}>
{o.name}
</NavLink>
));
return (
<div>
{id != null ?
<NavLink to={'/Home?id=' + id}>
<button>Change page</button>
</NavLink>
: null}
</div>
);
}
}
export default Home;
Basically I have a navigation bar that sets the page
from /Home
to Home?id=1
, Home?id=2
, etc when you click on it. It's a navlink with a onclick on it so we can refresh the id for the button "change page". I want the id to update everytime I click on this navlink.
The issue is I have with this code is that I have to click it twice for it to update the onpage button to be the correct id assuming im not already on the correct id link. How would I achieve this ?
Upvotes: 4
Views: 32115
Reputation: 24234
ComponenentDidMount
is called after render. This is the order of calls of react Hooks:
componentWillMount --> render --> componentDidMount
So you either move your refresh call this.refresh();
to your render method. Or else you can use componentWillMount
instead of componentDidMount
componentWillMount() {
// axios commands to get navigation bar setting it newpage state
this.refresh();
}
Upvotes: 1
Reputation: 91
There are a few anti-patterns here and I'd be unable to diagnose exactly what was wrong without seeing the project myself but from what you've described below should work. Unless you wanted deep linking in which you'd have to re-add the componentdidMount URL parameters fetch.
import { NavLink } from 'react-router-dom';
class Home extends Component {
constructor(props) {
super(props);
this.state = {
id: 0, // or whatever you want it to be initially
};
this.incrementId = this.incrementId.bind(this);
}
incrementId() {
this.setState({
id: id++
})
}
render() {
return (
<div>
<NavLink to={"/Home?id=" + this.state.id} onClick={() => this.incrementId()}>
<Button>Change page</Button>
</NavLink>
: null
</div>
);
}
}
export default Home;
I hope this helps at all.
Upvotes: 0
Reputation: 29989
@lt1's answer is spot on (and you should mark it as correct), but I'll just modify your example to help illustrate the point.
import React, { Component } from 'react';
import { NavLink } from 'react-router-dom';
class Home extends Component {
constructor(props) {
super(props);
this.state = {
newpage: '',
};
}
get currentId() {
const urlParams = new URLSearchParams(window.location.search);
return urlParams.get('id');
}
render() {
const id = this.currentId;
const newpage = this.state.newpage.map(o => (
<NavLink to={'/Home?id=' + o.id} onClick={this.refresh}>
{o.name}
</NavLink>
));
return (
<div>
{id != null ?
<NavLink to={'/Home?id=' + id}>
<button>Change page</button>
</NavLink>
: null}
</div>
);
}
}
export default Home;
Upvotes: 1
Reputation: 781
if I'm understanding the question correctly, it sounds like the issue boils down to the value of this.state.id not being up to date in your render
method.
One way to resolve that would be to just not store that on state at all- because it can already be derived from window.location.search
, you can just directly access it from that within the render method (using the first two lines of your refresh
method.)
in general, it's best to only store things on state that cannot be derived with some sort of calculation in the render method- otherwise you're essentially duplicating state from somewhere else (in this case, from window.location.search). There are some exceptions to this, but I think it's a good rule of thumb.
Upvotes: 1