Reputation: 1589
Is it possible to access state variables outside of render()
, but inside react custom component method?
componentDidMount() {
fetch(
"some url here"
)
.then(res => res.json())
.then(json => {
const days = this.getRainyDays(json)
this.setState({
data: json,
rainyDays: days
});
});
}
getRainyDays = (data) => {
console.log('data inside getRainyDays', this.state.data) // this.state.data is undefined here
console.log('data inside getRainyDays2', data) // data returns json fine
}
render() {
console.log(this.state.data) // this.state.data is fine too.
return (
<div className="App">
<header className="App-header">
Calendar showing {this.state.rainyDays} rainy days
</header>
<Year weatherData={this.state.data} />
<Weather />
</div>
);
}
Upvotes: 1
Views: 4819
Reputation: 4425
Yes, it is possible to access state inside of a component outside of the render
method.
According to the React
documentation:
setState()
does not always immediately update the component. It may batch or defer the update until later. This makes readingthis.state
right after callingsetState()
a potential pitfall.
Since your initial state most likely doesn't have the data
property set to some value, it comes back as undefined
.
You're trying to access this.state.data
inside of getRainyDays
before you even call this.setState
inside of componentDidMount
:
componentDidMount() {
fetch(...)
.then(json => {
const days = this.getRainyDays(json)
this.setState(...)
})
}
getRainyDays = (data) => {
console.log('data inside getRainyDays', this.state.data)
}
But even if you called this.getRainyDays
after this.setState
, you cannot rely on this.setState
updating your state immediately.
Again, from React
documentation:
Think of
setState()
as a request rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately.
If you would like to double check, however, that your state updates correctly, you can pass a callback to setState
that will get called after setState
updates component's state, like so:
componentDidMount() {
fetch(..)
.then(res => res.json())
.then(json => {
const days = this.getRainyDays(json)
this.setState({
data: json,
rainyDays: days
}, () => {
console.log('data in state', this.state.data)
});
});
}
One thing that I'd recommend, is to check, inside your render
function, whether state has the right data in it before you return some JSX
. You might run into issues where some components expects an array of items and it renders it immediately, but you're passing undefined
to it and it crashes...
render() {
// exit early and return `null` so that nothing gets rendered
// if your API call hasn't finished
if (!this.state.data || !this.state.rainyDays) {
return null
}
return (
<div className="App">
<header className="App-header">
Calendar showing {this.state.rainyDays} rainy days
</header>
<Year weatherData={this.state.data} />
<Weather />
</div>
);
}
Upvotes: 1