web-dev-qa-db-ja.com

setStateにReact=でfetch()APIを使用する方法

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で「デフォルト」をレンダリングします。ここで何が間違っていますか?

8
albert

エラーメッセージは、問題の内容を正確に示しています。

未定義の状態を設定できません

そのため、その時点で存在しないオブジェクトのメソッドとしてsetStateを呼び出そうとしています。どのオブジェクトのプロパティとして、setStateをメソッドとして呼び出そうとしていますか?

this.setState({apiInfo:jsonStr});

はい、あなたのthisが問題です。あなたがそれを呼び出そうとしている時点で-すなわちfetch呼び出しの.then()の中-thisは実際には未定義です。これは、Chrome Devtools:

Chrome Devtools shows this=undefined 私はthisがJavaScriptで滑りやすい顧客であるのではないかと心配しています。その値は、アプリの現在のコンテキストに応じて変化する可能性があります(実際に変化します)。

これを回避する方法はいくつかあります。少し不格好な(しかし機能します!)方法は、.fetch()呼び出しを入力する前にthis値をキャプチャし、別の変数に割り当てることです。この目的で使用されるthatまたはself変数がよく見られますが、これらは単なる慣例です。好きな変数を呼び出すことができます。

thisthatにキャプチャし、.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です。

18
ChillyPenguin

間違ったコンテキストでアクセスしているため、setStateは未定義です。関数を矢印関数に変換するか、適切なコンテキストにバインドできます。 ここ は、これをReactコンポーネントメソッドにバインドする時期と理由を説明する記事です。

コードで行うことができる変更は、それをバインドすることです

.then(function(jsonStr){
          this.setState({apiInfo: jsonStr});
          console.log(jsonStr);
      }.bind(this));

または矢印機能を使用して

.then((jsonStr)=>{
          this.setState({apiInfo: jsonStr});
          console.log(jsonStr);
      });
2
_ componentDidMount() {
    fetch('https://fcctop100.herokuapp.com/api/fccusers/top/recent')
      .then(response => response.json())
      .then(data => this.setState({ apiInfo: data }));
  }
_

レンダリング関数では、単に_this.state.apiInfo_を実行することはできません。このデータはオブジェクトの配列です。各オブジェクトにはusernameimgなどのキーがあります。 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を使用します。この事実を使用して、コールバックに矢印関数を渡すことができます。

0
Omar