問題点
例えば以下のように、バックグラウンドで取得したデータを表示させたいとします。
xxx.js
constructor(props) {
super(props);
this.state = {
result: {}
}
fetch("http://localhost/api/test")
.then(response => response.json())
.then(json => this.setState({ result: json }));
// /api/testは、以下のようなレスポンスを返す
// {
// test1 : "aaa",
// test2 : {
// test3 : "bbb"
// }
// }
}
render() {
return (
<div>
<p>{this.state.result.test1}</p> // "aaa"が表示される
<p>{this.state.result.test2.test3}</p> // "bbb"が出てほしいがエラーになる
</div>
)
}
このとき、this.state.result.test2.test3の部分で、以下のようなエラーが出てしまいます。
Cannot read property 'test3' of undefined
test3 の親であるthis.state.result.test2がundefinedですよ、というエラーです。
原因
恐らく、this.state.resultの中身が全部セットされる前にrenderメソッドが動いてしまっているためだと思います。
解決法
1.描画前にチェックを行う
undefinedチェックを入れてあげると、エラーなく動くようになります。
xxx.js
render() {
return (
<div>
<p>{this.state.result.test1}</p> // "aaa"が表示される
<p>{this.state.result.test2 ? this.state.result.test2.test3 : ""}</p> // "bbb"が表示される
</div>
)
}
JSX内ではif文が使えないので、三項演算子を使っています。
2.あらかじめ空のプロパティをセットしておく
どのような要素が返ってくるかが最初からわかっているのであれば、以下のように予めセットしておくことでも対応できます。
xxx.js
constructor(props) {
super(props);
this.state = {
result: {
test2 : {} // あらかじめ空をセットしておく
}
}
fetch("http://localhost/api/test")
.then(response => response.json())
.then(json => this.setState({ result: json }));
}
render() {
return (
<div>
<p>{this.state.result.test1}</p> // "aaa"が表示される
<p>{this.state.result.test2.test3}</p> // "bbb"が表示される
</div>
)
}
最後に
もっといい方法がありそうな気もするので、何かわかったら追記します。