I'm currently learning React, and some stuff are not so easy for a newbie...
I have a simple component which renders
this (note that it renders a li
array thanks to function getSlots
):
render () {
return (
<ul>
{this.getSlots(this.state.viewing).map(item => <li key={item}>{item}</li>)}
</ul>
)
}
Function getSlots
is:
constructor (props) {...}
getSlots (viewing) {
SOME STUFF...
const monday = this.state.house.monday
return SOME STUFF...
}
componentDidMount () {...}
render () {...}
The point is that getSlots
needs data to be fetched in componendDidMount
to work. Indeed, at this time, getSlots
doesn't work (it crashes) because it runs before data are fetched (this.state.house.monday
is "empty" when it runs).
How do I wait for data to be fetched before running getSlots
? Thanks for your clue.
I'm currently learning React, and some stuff are not so easy for a newbie...
I have a simple component which renders
this (note that it renders a li
array thanks to function getSlots
):
render () {
return (
<ul>
{this.getSlots(this.state.viewing).map(item => <li key={item}>{item}</li>)}
</ul>
)
}
Function getSlots
is:
constructor (props) {...}
getSlots (viewing) {
SOME STUFF...
const monday = this.state.house.monday
return SOME STUFF...
}
componentDidMount () {...}
render () {...}
The point is that getSlots
needs data to be fetched in componendDidMount
to work. Indeed, at this time, getSlots
doesn't work (it crashes) because it runs before data are fetched (this.state.house.monday
is "empty" when it runs).
How do I wait for data to be fetched before running getSlots
? Thanks for your clue.
3 Answers
Reset to default 10You're going to need to conditionally render. Provide a loading state to be loaded prior to asynchronously required data. You'll want something like the following:
class WrapperComponent extends PureComponent {
constructor(props) {
super(props);
this.state = {
isLoaded: false,
data: null
};
}
componentDidMount() {
MyApiCall.then(
res => this.setState({
// using spread operator, you will need transform-object-rest-spread from babel or
// another transpiler to use this
...this.state, // spreading in state for future proofing
isLoaded: true,
data: res.data
})
);
}
render() {
const { isLoaded, data } = this.state;
return (
{
isLoaded ?
<PresentaionComponentThatRequiresAsyncData data={ data } /> :
<LoadingSpinner /> // or whatever loading state you want, could be null
}
);
}
}
constructor() {
super()
this.state = { isLoading: true }
}
componentDidMount() {
('fetch data').then(() => { this.setState({ isLoading: false }); })
}
render() {
return (
<div>
{!this.state.isLoading && ('your code')}
</div>
);
}
Something like that.
You can initialize the state with empty data before fetching, in constructor
like this
constructor(){
....,
this.state = { house: null}
}
And put a condition in getSlots
method which checks if data is fetched or not
getSlots (viewing) {
if (!this.state.house) {
return [];
}
SOME STUFF...
const monday = this.state.house.monday
return SOME STUFF...
}
When the data arrives, then simply set the corresponding state like this
componentDidMount(){
fetch().then((houses) => {
this.setState({ houses: houses })
})
}
this.state.house
is not what you expect. – Bergi Commented Dec 16, 2017 at 21:29