Fetch =)APIを使用してWebサイトからデータを取得し、setStateを使用してデータに等しい状態を設定し、最後にレンダリングするコンポーネントをReactで記述しようとしています。データ。私のコードは次のようになります。
import React from 'react';
export default class Test extends React.Component {
constructor(props){
super(props);
this.state = {apiInfo: 'default'};
}
componentDidMount(){
fetch('https://fcctop100.herokuapp.com/api/fccusers/top/recent').then(
function(response){
return response.json();
}
).then(function(jsonData){
return JSON.stringify(jsonData);
}
).then(function(jsonStr){
this.setState({apiInfo: jsonStr});
console.log(jsonStr);
});
}
render(){
return(
<tr>
<td>{this.state.apiInfo}</td>
</tr>
);
}
}
ただし、これは未定義のsetStateを設定できないというエラーが発生します。最終的にHTMLで「デフォルト」をレンダリングします。ここで何が間違っていますか?
エラーメッセージは、問題の内容を正確に示しています。
未定義の状態を設定できません
そのため、その時点で存在しないオブジェクトのメソッドとしてsetState
を呼び出そうとしています。どのオブジェクトのプロパティとして、setState
をメソッドとして呼び出そうとしていますか?
this.setState({apiInfo:jsonStr});
はい、あなたのthis
が問題です。あなたがそれを呼び出そうとしている時点で-すなわちfetch
呼び出しの.then()
の中-this
は実際には未定義です。これは、Chrome Devtools:
私はthis
がJavaScriptで滑りやすい顧客であるのではないかと心配しています。その値は、アプリの現在のコンテキストに応じて変化する可能性があります(実際に変化します)。
これを回避する方法はいくつかあります。少し不格好な(しかし機能します!)方法は、.fetch()呼び出しを入力する前にthis
値をキャプチャし、別の変数に割り当てることです。この目的で使用されるthat
またはself
変数がよく見られますが、これらは単なる慣例です。好きな変数を呼び出すことができます。
this
をthat
にキャプチャし、.then()
内でthat
を呼び出して、componentDidMount()メソッドを作り直した方法を次に示します。
componentDidMount() {
const that = this;
fetch("https://fcctop100.herokuapp.com/api/fccusers/top/recent")
.then(function(response) {
return response.json();
})
.then(function(jsonData) {
return JSON.stringify(jsonData);
})
.then(function(jsonStr) {
that.setState({ apiInfo: jsonStr });
console.log(jsonStr);
});
}
矢印関数の使用に慣れている場合、別の方法は、「通常の」関数呼び出しを次のように置き換えることです。
.then(jsonStr => {
this.setState({ apiInfo: jsonStr });
console.log(jsonStr);
});
矢印関数のthis
は、常にその親が定義したthis
です。
間違ったコンテキストでアクセスしているため、setState
は未定義です。関数を矢印関数に変換するか、適切なコンテキストにバインドできます。 ここ は、これをReactコンポーネントメソッドにバインドする時期と理由を説明する記事です。
コードで行うことができる変更は、それをバインドすることです
.then(function(jsonStr){
this.setState({apiInfo: jsonStr});
console.log(jsonStr);
}.bind(this));
または矢印機能を使用して
.then((jsonStr)=>{
this.setState({apiInfo: jsonStr});
console.log(jsonStr);
});
_ componentDidMount() {
fetch('https://fcctop100.herokuapp.com/api/fccusers/top/recent')
.then(response => response.json())
.then(data => this.setState({ apiInfo: data }));
}
_
レンダリング関数では、単に_this.state.apiInfo
_を実行することはできません。このデータはオブジェクトの配列です。各オブジェクトにはusername
img
などのキーがあります。 render
関数の内部でreturn
の外部でconsole.log(this.state.apiInfo)
を実行すると、それがわかります。
配列値内の各オブジェクトにアクセスして表示するには、map
配列を使用してapiInfo
を実行します。
_render() {
const { apiInfo } = this.state;
apiInfo && console.log(apiInfo.map(item => item.img));
return (
<div>
{apiInfo &&
apiInfo.map(item => <div> {item.img} </div> )}
</div>
);
}
_
ブラウザーに付属するネイティブフェッチAPIは、JavaScript約束を使用して非同期応答を解決します。
データが正常に取得されると、Reactのthis.setState()メソッドを使用してローカル状態で保存されます。その後、render()メソッドが再びトリガーされ、取得したデータを表示できます。
矢印関数はES6で導入されました。矢印関数には独自のコンテキストがなく、代わりに定義されたコンテキストと同じthis
を使用します。この事実を使用して、コールバックに矢印関数を渡すことができます。