私は最近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>
)
}
}
この場合、 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>
);
}
}
Flux Architecture を調べてみてください。 React-Redux Implementation をチェックアウトすることもお勧めします。あなたのAPI呼び出しをあなたの行動に入れてください。すべてをコンポーネントに入れるよりもはるかにクリーンです。
アクションは、アプリケーションの状態を変更したりAPI呼び出しを行うために呼び出すことができる一種のヘルパーメソッドです。
状態を更新するには、fetch
内でcomponentDidMount
methodを使用します。以下のように
…….
componentDidMount(){
fetch('https://randomuser.me/api/')
.then(({ results }) => this.setState({ person: results }));
}
…….
Redux http://redux.js.org/index.html をご覧ください。
非同期呼び出し、つまりAPI呼び出しを処理する方法が明確に定義されているので、API呼び出しにjQueryを使用する代わりに、fetchまたはrequestnpmパッケージ、fetchis)を使用することをお勧めします。最近のブラウザでサポートされていますが、シムもサーバー側で利用可能です。
この他にも素晴らしいパッケージSUPERAGENTがあります。これは、APIリクエストを行うときに多くのオプションがあり、非常に使いやすいものです。
この議論はしばらく前に行われたもので、@ Alexander T.の回答は、私のように反応したい人のための良いガイドとなります。そして、初心者が最初に直面する可能性のあるおそらく一般的な問題について、この議論の方法を追加で共有します。
componentWillReceiveProps(nextProps)
、from official documentation :
Propの変更に応じて状態を更新する必要がある場合(たとえば、リセットする場合)、this.propsとnextPropsを比較し、このメソッドでthis.setState()を使用して状態遷移を実行できます。
ここに、親コンポーネントからのurlまたはpropsから来て、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()
は廃止されます。
ここにあるのは、ライフサイクル内のsomeメソッド( Doc 内のすべて)メソッドのみで、APIのデプロイに関連すると思われます一般的なケース:
上の図を参照してください:
にAPIをデプロイcomponentDidMount()
ここでAPI呼び出しを行う適切なシナリオは、このコンポーネントのコンテンツ(APIの応答から)が静的であり、componentDidMount()
はコンポーネントのマウント中に1回だけ起動し、新しいコンポーネントも親コンポーネントから渡されるか、アクションを持つre-rendering
をリードします。
コンポーネントは、re-renderとの違いをチェックしますが、re-mount。
引用 doc :
リモートエンドポイントからデータをロードする必要がある場合、これはネットワーク要求をインスタンス化するのに適した場所です。
static getDerivedStateFromProps(nextProps, prevState)
現在のコンポーネントには2種類のコンポーネント更新、setState()
がありますはnotこのメソッドをトリガーに導きますが、parentからの再レンダリングまたは新しいプロップcomponentします。このメソッドはマウント中にも起動することがわかりました。
これは、テンプレートのような現在のコンポーネントを使用する場合、APIをデプロイする適切な場所であり、APIの新しいパラメーターは親コンポーネントからのプロパティです 。
APIから異なる応答を受け取り、このstate
をここに返して、このコンポーネントのコンテンツを変更します。
例えば:
親コンポーネントのさまざまな車のドロップダウンリストがあります。このコンポーネントでは、選択した車の詳細を表示する必要があります。
componentDidUpdate(prevProps, prevState)
static getDerivedStateFromProps()
とは異なり、このメソッドは初期レンダリングを除くすべてのレンダリングの直後に呼び出されます。 API呼び出しを使用して、1つのコンポーネントに違いを表示できます。
前の例を拡張します。
車の詳細を表示するコンポーネントには、この車のシリーズのリストが含まれる場合があります。2013年の生産モデルを確認する場合は、リスト項目をクリックまたは選択するか、最初のsetState()
この振る舞い(リスト項目の強調表示など)をこのコンポーネントに反映し、次のcomponentDidUpdate()
で新しいパラメーター(状態)でリクエストを送信します。応答を取得した後、車の詳細のさまざまなコンテンツをレンダリングするためにsetState()
再び。次のcomponentDidUpdate()
が無限ループを引き起こさないようにするには、このメソッドの最初でprevState
を使用して状態を比較し、APIを送信して新しいコンテンツをレンダリングするかどうかを決定する必要があります。
このメソッドは、小道具でstatic getDerivedStateFromProps()
と同じように実際に利用できますが、props
を利用してprevProps
の変更を処理する必要があります。そして、componentDidMount()
と協力して、最初のAPI呼び出しを処理する必要があります。
doc からの引用:
...これは、現在の小道具を前の小道具と比較する限り、ネットワーク要求を行うのにも適した場所です...
レンダリング機能は純粋であるべきです、それはそれがレンダリングするために状態と小道具だけを使用することを意味します。 React Appでデータの取得とレンダリングの問題を分離している場合も、これは良い点です。このアイデアをよく説明しているこの記事を読むことをお勧めします。 https://medium.com/@learnreact/container-components-c0e67432e005#.sfydn87nm
React v16 ドキュメントからのこの部分はあなたの質問に答えるでしょう、componentDidMount()について読んでください:
componentDidMount()
componentDidMount()は、コンポーネントがマウントされた直後に呼び出されます。 DOMノードを必要とする初期化はここに行くべきです。リモートエンドポイントからデータをロードする必要がある場合、これはネットワーク要求をインスタンス化するのに適した場所です。この方法は、購読を設定するのに適した場所です。その場合は、componentWillUnmount()で登録解除することを忘れないでください。
ご覧のとおり、 componentDidMount は api呼び出し を実行するのに最適な場所およびサイクルであると考えられ、ノードにもアクセスします。もしあなたがjQueryを使っているのであれば、document. ready()関数を思い出させるはずです。
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 />}
コードの説明は VIDEO にあります。 try/catch関数を使用してcomponentDidMount内で非同期API呼び出しを行うクリーンな方法: UserList.js
import React, { Component } from "react";
import "./UserList.css";
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 className="list__container">
{userList.length > 0 && userList.map(user => (
<div className="list__item" key={user}>
<img src={user.picture.medium} className="list-item__photo" alt="user"/>
<div className="list-item__info-wrap">
<div className="list-item__name">{user.name.first}{user.name.last}</div>
<div className="list-item__phone">{user.phone}</div>
<div className="list-item__email">{user.email}</div>
</div>
</div>
))}
{error && <div>Sorry, can not display the data</div>}
</div>
)
}}
UserList.css
.list__container {
background: #0f0f0f;
color: #f2f2f2;
padding: 30px 0;
text-align: center;
}
.list__item {
display: flex;
align-items: center;
justify-content: center;
}
.list-item__photo {
width: 100px;
height: 100px;
border-radius: 50%;
}
.list-item__info-wrap {
margin-left: 20px;
text-align: left;
}
.list-item__name {
text-transform: capitalize;
}