反応jsでAPI呼び出しを行う正しい方法は何ですか?


137

私は最近AngularからReactJに移りました。API呼び出しにjQueryを使用しています。リストに印刷されるランダムなユーザーリストを返すAPIがあります。

API呼び出しの記述方法がわかりません。このためのベストプラクティスは何ですか?

以下を試しましたが、何も出力されません。必要に応じて、代替のAPIライブラリを実装できます。

以下は私のコードです:

import React from 'react';

export default class UserList extends React.Component {    
  constructor(props) {
    super(props);
    this.state = {
      person: []
    };
  }

  UserList(){
    return $.getJSON('https://randomuser.me/api/')
    .then(function(data) {
      return data.results;
    });
  }

  render() {
    this.UserList().then(function(res){
      this.state = {person: res};
    });
    return (
      <div id="layout-content" className="layout-content-wrapper">
        <div className="panel-list">
          {this.state.person.map((item, i) =>{
            return(
              <h1>{item.name.first}</h1>
              <span>{item.cell}, {item.email}</span>
            )
          })}
        <div>
      </div>
    )
  }
}

2
使用している状態管理ライブラリによって異なります。何も使用していない場合は、API呼び出しを別のファイルに移動し、状況に応じてAPI関数をcomponentDidMountコールバックで呼び出すことができます。
16

fetch()Ajaxリクエストを行うためにjQueryのみを使用する場合は、jQueryの代わりに使用できます。
フレッド

Jqueryを使用する理由 jqueryは巨大なライブラリであり、それは不要です
Robin

ここに追加するだけで、useEffectおそらく現在api呼び出しを配置する場所です。btholt.github.io/complete-intro-to-react-v5/effects
shw

回答:


98

この場合、内componentDidMountでajax呼び出しを実行してから、更新できます。state

export default class UserList extends React.Component {
  constructor(props) {
    super(props);

    this.state = {person: []};
  }

  componentDidMount() {
    this.UserList();
  }

  UserList() {
    $.getJSON('https://randomuser.me/api/')
      .then(({ results }) => this.setState({ person: results }));
  }

  render() {
    const persons = this.state.person.map((item, i) => (
      <div>
        <h1>{ item.name.first }</h1>
        <span>{ item.cell }, { item.email }</span>
      </div>
    ));

    return (
      <div id="layout-content" className="layout-content-wrapper">
        <div className="panel-list">{ persons }</div>
      </div>
    );
  }
}

2
それは..あなたは「1がより良い状態管理のための最高のライブラリがある」私を提案してくださいでした、おかげで働いていた
ラジRjの

3
@Raj Rj最近のReduxだと思います
Alexander T.

8
最近のReduxの人気は高く、そのスタイルは関数型プログラミングに由来しています。OOPスタイルの場合、Mobx(mobxjs.github.io/mobx)は優れた状態管理ライブラリであり、ビジネスコードの作成に集中でき、最終的にボイラープレートコードを削減できます
Nhan Tran

25

Flux Architectureをチェックしてみてください。React-Reduxの実装も確認することをお勧めします。あなたのAPI呼び出しをあなたのアクションに入れてください。すべてをコンポーネントに配置するよりもはるかにクリーンです。

アクションは、アプリケーションの状態を変更したり、API呼び出しを行ったりするために呼び出すことができる一種のヘルパーメソッドです。


Troperありがとうございます。では、API関連の呼び出しを別のファイルに保存する必要がありますか?また、「コンポーネントクラス」でそれらをどのように呼び出すのですか?どのフォルダ構造に従うべきですか?ベストプラクティスは何ですか?PS-私は反応するのが初めてなので、この基本的な質問をする。
Raj Rj

reduxの実装では、アクションメソッドがコンポーネントに注入されます。これらのメソッドは、コンポーネントのプロップになり、呼び出すことができます。構造については、react-redux-starter-kitをチェックアウトできます。
Jei Trooper、2016

12

fetch内部のメソッドを使用してcomponentDidMount状態を更新します。

componentDidMount(){
  fetch('https://randomuser.me/api/')
      .then(({ results }) => this.setState({ person: results }));
}

11

この議論はしばらくの間行われており、@ Alexander T.の回答は、私のようなReactの新しい人がフォローするための良いガイドを提供してくれました。そして、コンポーネントを更新するために同じAPIを複数回呼び出すことに関するいくつかの追加のノウハウを共有します。これは、初心者が最初に直面する可能性のある一般的な問題だと思います。

componentWillReceiveProps(nextProps)公式ドキュメントから:

プロップの変更に応じて状態を更新する必要がある場合(たとえば、状態をリセットする場合)、this.propsとnextPropsを比較し、このメソッドでthis.setState()を使用して状態遷移を実行できます。

ここが親コンポーネントからの小道具を処理し、API呼び出しを行い、状態を更新する場所であると結論付けることができます。

@Alexander T.の例に基づく:

export default class UserList extends React.Component {
  constructor(props) {
    super(props);
    this.state = {person: []};
  }

  componentDidMount() {
   //For our first load. 
   this.UserList(this.props.group); //maybe something like "groupOne"
  }

  componentWillReceiveProps(nextProps) {
    // Assuming parameter comes from url.
    // let group = window.location.toString().split("/")[*indexParameterLocated*];
    // this.UserList(group);

    // Assuming parameter comes from props that from parent component.
    let group = nextProps.group; // Maybe something like "groupTwo" 
    this.UserList(group);
  }

  UserList(group) {
    $.getJSON('https://randomuser.me/api/' + group)
      .then(({ results }) => this.setState({ person: results }));
  }

  render() {
    return (...)
  }
}

更新

componentWillReceiveProps() 廃止されるでしょう。

以下は、一般的なケースでAPIのデプロイに関連すると思われるライフサイクルの一部のメソッド(すべてDoc内のメソッド)です。 ここに画像の説明を入力してください

上の図を参照してください。

  • にAPIをデプロイ componentDidMount()

    ここでAPI呼び出しを行う適切なシナリオは、このコンポーネントの(APIの応答からの)コンテンツが静的でcomponentDidMount()あり、コンポーネントのマウント中に一度だけ発生し、新しいプロップが親コンポーネントから渡されるか、アクションをリードすることre-renderingです。
    コンポーネントは違いをチェックして再レンダリングしますが、再マウントはしません。ドキュメント
    からの引用:

リモートエンドポイントからデータをロードする必要がある場合、これはネットワーク要求をインスタンス化するのに適した場所です。


  • にAPIをデプロイ static getDerivedStateFromProps(nextProps, prevState)

私たちは、二種類のがあることに気づくべきでコンポーネントの更新setState() 現在のコンポーネントでなりませんトリガにこの方法を導くが、しかしからの再レンダリングするか、新しい小道具親コンポーネントを行います。このメソッドはマウント中にも実行されることがわかりました。

テンプレートのような現在のコンポーネントを使用したい場合、これはAPIをデプロイするのに適切な場所であり、APIの新しいパラメーターは親コンポーネントからのプロップです
APIから別の応答を受け取り、stateここに新しい応答を返し、このコンポーネントのコンテンツを変更します。

例:
親コンポーネントに異なる車のドロップダウンリストがあります。このコンポーネントは、選択された車の詳細を表示する必要があります。


  • にAPIをデプロイ componentDidUpdate(prevProps, prevState)

とは異なりstatic getDerivedStateFromProps()、このメソッドは、初期レンダリングを除くすべてのレンダリングの直後に呼び出されます。API呼び出しを使用して、1つのコンポーネントで差異をレンダリングできます。

前の例を拡張
します。車の詳細を表示するコンポーネントには、この車のシリーズのリストが含まれている可能性があります。2013年の生産を確認したい場合は、リストアイテムをクリックまたは選択するか...最初setState()にリードしてこれを反映しますこのコンポーネントの動作(リストアイテムの強調表示など)、および以下でcomponentDidUpdate()は新しいパラメーター(状態)を使用してリクエストを送信します。応答を受け取った後setState()、車の詳細のさまざまなコンテンツをレンダリングするために再び。以下componentDidUpdate()が無限ループを引き起こさないようにするにはprevState、このメソッドの最初に利用して状態を比較し、APIを送信して新しいコンテンツをレンダリングするかどうかを決定する必要があります。

この方法は実際にはstatic getDerivedStateFromProps()小道具と同じように利用できますが、propsを利用しての変更を処理する必要がありprevPropsます。またcomponentDidMount()、最初のAPI呼び出しを処理するために連携する必要があります。

ドキュメントからの引用:

...これは、現在の小道具を以前の小道具と比較している限り、ネットワーク要求を行うのにも良い場所です...


10

redux http://redux.js.org/index.htmlをご覧ください

彼らは非同期呼び出し、つまりAPI呼び出しを処理する非常に明確な方法を持っています。API呼び出しにjQueryを使用する代わりに、フェッチまたはリクエスト npmパッケージを使用することをお勧めします。フェッチは現在、最新のブラウザーでサポートされていますが、シムも利用可能ですサーバ側。

この別の素晴らしいパッケージsuperagentもあり、APIリクエストを行うときに多くのオプションがあり、非常に使いやすいです。


3

レンダリング関数は純粋でなければなりません。つまり、レンダリングに状態と小道具のみを使用し、レンダリングで状態を変更しようとしないでください。これは通常、醜いバグを引き起こし、パフォーマンスを大幅に低下させます。また、React Appでデータの取得を分離して懸念事項を表示する場合にも、これは良い点です。このアイデアを非常によく説明しているこの記事を読むことをお勧めします。https://medium.com/@learnreact/container-components-c0e67432e005#.sfydn87nm


3

React v16ドキュメントのこの部分は、componentDidMount()について読んで、あなたの質問に答えます:

componentDidMount()

componentDidMount()は、コンポーネントがマウントされた直後に呼び出されます。DOMノードを必要とする初期化はここに行ってください。リモートエンドポイントからデータをロードする必要がある場合、これはネットワーク要求をインスタンス化するのに適した場所です。このメソッドは、サブスクリプションをセットアップするのに適した場所です。その場合は、componentWillUnmount()でサブスクライブを解除することを忘れないでください。

ご覧のとおり、componentDidMountapi呼び出しを実行し、ノードにアクセスするのに最適な場所とサイクルであると考えられています。つまり、この時点で、呼び出し、ビューの更新、またはドキュメントの準備ができているときにできることは何でも安全です。 jQueryを使用すると、どういうわけかdocument.ready()関数を思い出させるはずです。ここで、コードで実行したいすべてのことに対してすべてが準備できていることを確認できます...


3

1)F etch APIを使用して、エンドポイントからデータをフェッチできます。

Githubユーザーのすべてのレポーズをフェッチする例

  /* Fetch GitHub Repos */
  fetchData = () => {

       //show progress bar
      this.setState({ isLoading: true });

      //fetch repos
      fetch(`https://api.github.com/users/hiteshsahu/repos`)
      .then(response => response.json())
      .then(data => {
        if (Array.isArray(data)) {
          console.log(JSON.stringify(data));
          this.setState({ repos: data ,
                         isLoading: false});
        } else {
          this.setState({ repos: [],
                          isLoading: false  
                        });
        }
      });
  };

2)他の選択肢はAxiosです

axiosを使用すると、httpリクエストの結果を.json()メソッドに渡す中間ステップを省略できます。Axiosは期待するデータオブジェクトを返すだけです。

  import axios from "axios";

 /* Fetch GitHub Repos */
  fetchDataWithAxios = () => {

     //show progress bar
      this.setState({ isLoading: true });

      // fetch repos with axios
      axios
          .get(`https://api.github.com/users/hiteshsahu/repos`)
          .then(result => {
            console.log(result);
            this.setState({
              repos: result.data,
              isLoading: false
            });
          })
          .catch(error =>
            this.setState({
              error,
              isLoading: false
            })
          );
}

これで、この戦略のいずれかを使用してデータをフェッチすることを選択できます componentDidMount

class App extends React.Component {
  state = {
    repos: [],
   isLoading: false
  };

  componentDidMount() {
    this.fetchData ();
  }

その間、データの読み込み中にプログレスバーを表示できます

   {this.state.isLoading && <LinearProgress />}

2

関数コンポーネントのフックを使用してデータをフェッチすることもできます

API呼び出しの完全な例:https : //codesandbox.io/s/jvvkoo8pq3

2番目の例:https : //jsfiddle.net/bradcypert/jhrt40yv/6/

const Repos = ({user}) => {
  const [repos, setRepos] = React.useState([]);

  React.useEffect(() => {
    const fetchData = async () => {
        const response = await axios.get(`https://api.github.com/users/${user}/repos`);
        setRepos(response.data);
    }

    fetchData();
  }, []);

  return (
  <div>
    {repos.map(repo =>
      <div key={repo.id}>{repo.name}</div>
    )}
  </div>
  );
}

ReactDOM.render(<Repos user="bradcypert" />, document.querySelector("#app"))

1

外部API呼び出しの最良の場所と実践は、React LifecycleメソッドのcomponentDidMount()です。API呼び出しの実行後、ローカル状態を更新して新しいrender()メソッド呼び出しをトリガーする必要があります。更新されたローカル状態の変更は、コンポーネントビューに適用されます。

React での初期外部データソース呼び出しの他のオプションとして、クラスのconstructor()メソッドが指定されています。コンストラクターは、コンポーネントオブジェクトインスタンスの初期化時に実行される最初のメソッドです。このアプローチは、高次コンポーネントのドキュメントの例で見ることができます

メソッドcomponentWillMount()およびUNSAFE_componentWillMount()は、非推奨となることを目的としているため、外部API呼び出しには使用しないでください。ここでは、この方法が廃止される一般的な理由を確認できます。

いずれにしても、render()メソッドまたはrender()から直接呼び出されたメソッドを外部API呼び出しのポイントとして使用してはなりませ。これを行うと、アプリケーションがブロックされます。


0

クリーンな方法は、try / catch関数を使用して、componentDidMount内で非同期API呼び出しを行うことです。

APIを呼び出すと、応答を受け取ります。次に、JSONメソッドを適用して、応答をJavaScriptオブジェクトに変換します。次に、その応答オブジェクトから、 "results"(data.results)という名前の子オブジェクトのみを取得します。

最初に、状態の「userList」を空の配列として定義しました。API呼び出しを行い、そのAPIからデータを受信したらすぐに、setStateメソッドを使用して「結果」をuserListに割り当てます。

render関数の内部では、userListが状態から来ることを伝えています。userListはマップするオブジェクトの配列なので、各オブジェクト「user」の写真、名前、電話番号を表示します。この情報を取得するには、ドット表記(user.phoneなど)を使用します。

:APIによっては、応答が異なる場合があります。Console.logで「応答」全体を調べて、必要な変数を確認し、setStateで割り当てます。

UserList.js

import React, { Component } from "react";

export default class UserList extends Component {
   state = {
      userList: [], // list is empty in the beginning
      error: false
   };

   componentDidMount() {
       this.getUserList(); // function call
   }

   getUserList = async () => {
       try { //try to get data
           const response = await fetch("https://randomuser.me/api/");
           if (response.ok) { // ckeck if status code is 200
               const data = await response.json();
               this.setState({ userList: data.results});
           } else { this.setState({ error: true }) }
       } catch (e) { //code will jump here if there is a network problem
   this.setState({ error: true });
  }
};

  render() {
  const { userList, error } = this.state
      return (
          <div>
            {userList.length > 0 && userList.map(user => (
              <div key={user}>
                  <img src={user.picture.medium} alt="user"/>
                  <div>
                      <div>{user.name.first}{user.name.last}</div>
                      <div>{user.phone}</div>
                      <div>{user.email}</div>
                  </div>
              </div>
            ))}
            {error && <div>Sorry, can not display the data</div>}
          </div>
      )
}}

0

キャンセル、インターセプターなどをサポートするAPIリクエストにaxiosを使用するのは素晴らしいことです。axiosとともに、状態管理にはreact-reduxを使用し、副作用にはredux-saga / redux-thunkを使用します。


これは誤りではありませんが、axiosとreduxを使用することは、データをフェッチして状態を管理するための有効な方法であるため、実際には質問に答えず、コメントに近いものです。
エミールベルジェロン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.