web-dev-qa-db-ja.com

React.jsでAxiosでAsync / Awaitを使用する

以下

reactでaxiosでasync/awaitを使用する方法

React.jsアプリでAsync/Awaitを使用して、サーバーに単純なgetリクエストを作成しようとしています。サーバーは次のような/dataに単純なJSONをロードします

JSON

{
   id: 1,
   name: "Aditya"
}

単純なjquery ajax getメソッドを使用して、Reactアプリにデータを取得できます。ただし、axiosライブラリとAsync/Awaitを使用して、ES7標準に準拠したいと考えています。私の現在のコードは次のようになります。

class App extends React.Component{
 async getData(){
     const res = await axios('/data');
     console.log(res.json());
 }
 render(){
     return(
         <div>
             {this.getData()}
         </div>
     );
 }
}

このアプローチを使用すると、次のエラーが発生します。

オブジェクトはReact子としては無効です(見つかった:[object Promise])。子のコレクションをレンダリングする場合は、代わりに配列を使用します。

正しく実装していませんか?

29
Singh

2つの問題が飛び出します。

  1. getDataは何も返さないため、そのプロミス(async関数は常にプロミスを返します)は、解決時にundefinedで解決されます

  2. エラーメッセージは、解決するのを待ってから解決をレンダリングするのではなく、promise getDataリターンを直接レンダリングしようとしていることを明確に示しています。

アドレス指定#1:getDataは、jsonを呼び出した結果をreturn返します:

async getData(){
   const res = await axios('/data');
   return await res.json();
}

Addressig#2:コードをもっと見る必要がありますが、基本的にはできません

<SomeElement>{getData()}</SomeElement>

...それは解決を待たないからです。代わりに、getDataを使用して状態を設定する必要があります。

this.getData().then(data => this.setState({data}))
              .catch(err => { /*...handle the error...*/});

...そしてその状態をレンダリング時に使用します:

<SomeElement>{this.state.data}</SomeElement>

更新:コードを見せたので、何かのようにする必要があります:

class App extends React.Component{
    async getData() {
        const res = await axios('/data');
        return await res.json(); // (Or whatever)
    }
    constructor(...args) {
        super(...args);
        this.state = {data: null};
    }
    componentDidMount() {
        if (!this.state.data) {
            this.getData().then(data => this.setState({data}))
                          .catch(err => { /*...handle the error...*/});
        }
    }
    render() {
        return (
            <div>
                {this.state.data ? <em>Loading...</em> : this.state.data}
            </div>
        );
    }
}

今後の更新:awaitおよびcomponentDidMountではなく、thencatchを使用する設定を指定しました。そのためには、async IIFE関数をその中に入れ子にして、関数がスローできないようにします。 (componentDidMount自体をasyncにすることはできません。その約束を消費するものは何もありません。)例:

class App extends React.Component{
    async getData() {
        const res = await axios('/data');
        return await res.json(); // (Or whatever)
    }
    constructor(...args) {
        super(...args);
        this.state = {data: null};
    }
    componentDidMount() {
        if (!this.state.data) {
            (async () => {
                try {
                    this.setState({data: await this.getData()});
                } catch (e) {
                    //...handle the error...
                }
            })();
        }
    }
    render() {
        return (
            <div>
                {this.state.data ? <em>Loading...</em> : this.state.data}
            </div>
        );
    }
}
28
T.J. Crowder

過去数か月の私の経験では、これを達成する最良の方法は次のとおりであることに気付きました。

class App extends React.Component{
  constructor(){
   super();
   this.state = {
    serverResponse: ''
   }
  }
  componentDidMount(){
     this.getData();
  }
  async getData(){
   const res = await axios.get('url-to-get-the-data');
   const { data } = await res;
   this.setState({serverResponse: data})
 }
 render(){
  return(
     <div>
       {this.state.serverResponse}
     </div>
  );
 }
}

クリックなどのイベントでポストリクエストを行おうとしている場合は、イベントでgetData()関数を呼び出し、その内容を次のように置き換えます。

async getData(username, password){
 const res = await axios.post('url-to-post-the-data', {
   username,
   password
 });
 ...
}

さらに、コンポーネントがロードされようとしているときにリクエストを行う場合は、async getData()async componentDidMount()に置き換え、レンダリング関数を次のように変更します。

render(){
 return (
  <div>{this.state.serverResponse}</div>
 )
}
11
Singh