Reputation: 129
I tried to read some data with some ajax request, but I am not sure if my code is correct. Here is the code:
interface IProps {
data: IScheduler;
}
interface IState {
list: IScheduler;
}
export default class Page extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = {
list: this.props.data,
};
}
public componentWillMount() {
this.getData();
}
public getData = () => {
axios.get(myURL)
.then( (response) => {
this.setState({list: response.data});
console.log(response.data.generatedDate); //works
})
.catch( (error) => {
console.log("DIDN'T CATCH DATA", error);
});
}
public render(): JSX.Element {
const data: IScheduler = this.state.list;
// getting an error
console.log(data.creationDate);
return (
<div className="container">
<MyListCmp data={data}/>
</div>
);
}
I see the error:
Uncaught TypeError: Cannot read property 'list' of undefined
When I try:
console.log(data); // or this.state.list
it's just undefined.
Data example:
{
"generatedDate": "12.12.2017",
"meetings": [
...
]
}
The same error occurs in the MyListCmp when I want to read 'meetings' or 'generatedDate':
Uncaught TypeError: Cannot read property 'generatedDate' of undefined
Uncaught TypeError: Cannot read property 'meetings' of undefined
How can I read it? Is this possible that in render() or return() data hasn't fetched yet?
I can tell that if I do like this:
const data: IScheduler = {
generatedDate: "12.12.2017",
meetings: [
...
]
}
It works, but this is not the point. I need to fetch it from some URL. I will appreciate every advice.
Upvotes: 3
Views: 6098
Reputation: 7664
This is an example of trying to depend on a value without checking it or providing a default. You wrote:
public render(): JSX.Element { const data: IScheduler = this.state.list; // getting an error console.log(data.creationDate);
render()
gets called early, probably before the response has time to come back. What you want to do is provide a way for it to render correctly even if the data isn't available yet. Often that means a loading animation, but you can also just conditionally render the data:
{this.state.list && <MyMeetingList meetings={this.state.list} />}
Why does this work?
The above is a common shortcut for "only do the second thing if the first thing evaluates truthy". If this.state.list
is undefined, that's falsy so the expression is short-circuit evaluated to false, and the JSX on the right hand side of the &&
is ignored.
Why is this useful?
React render
functions get called a lot. If you want to try an experiment sometime, put a breakpoint in render
or stick a log
in there. Depending on the complexity of the component and how often its data changes, you may be surprised how often it fires. This means it's going to be called at least once before any async operations have time to complete, and you need to think ahead about sensible defaults for any values it requires or (as above) test to see if they exist yet.
Upvotes: 2
Reputation: 276393
How can I read it? Is this possible that in render() or return() data hasn't fetched yet?
Yes. Hence the undefined
🌹
Upvotes: 0