ReactJSを使用して、students
とscores
の2つの異なるAPIポイントを取得して再構築しようとしています。どちらもオブジェクトの配列です。
私の目標は:最初に、生徒とスコアを取得し、次に、生徒とスコアを状態に保存して、それらを変更し、生徒とスコアの状態に基づいて新しい状態を作成します。つまり、getStudents
、getScores
、およびrearrangeStudentsAndScores
の3つの関数があります。 getStudents
とgetScores
は、rearrangeStudentsAndScores
を実行する前に終了する必要があります。
私の問題は:rearrangeStudentsAndScores
が完了する前にgetScores
が実行されることがあります。 rearrangeStudentsAndScores
を台無しにしました。しかし、時にはそれは完了するでしょう。なぜ50%の頻度で機能するのかはわかりませんが、100%の頻度で機能させる必要があります。
これは私がfetch
students and scores
Client
ファイル内:
function getStudents(cb){
return fetch(`api/students`, {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
}).then((response) => response.json())
.then(cb)
};
function getScores(cb){
return fetch(`api/scores`, {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
}).then((response) => response.json())
.then(cb)
};
次に、それらを結合しました。
function getStudentsAndScores(cbStudent, cbScores, cbStudentsScores){
getStudents(cbStudent).then(getScores(cbScores)).then(cbStudentsScores);
}
反応アプリには、次のものがあります。
getStudentsAndScores(){
Client.getStudentsAndScores(
(students) => {this.setState({students})},
(scores) => {this.setState({scores})},
this.rearrangeStudentsWithScores
)
}
rearrangeStudentsWithScores(){
console.log('hello rearrange!')
console.log('students:')
console.log(this.state.students);
console.log('scores:');
console.log(this.state.scores); //this returns [] half of the time
if (this.state.students.length > 0){
const studentsScores = {};
const students = this.state.students;
const scores = this.state.scores;
...
}
}
どういうわけか、rearrangeStudentsWithScores
、this.state.scores
は引き続き[]
。
this.state.students
およびthis.state.scores
を実行する前に両方ともロードされますrearrangeStudentsWithScores
?
コードは 継続コールバック とPromisesを組み合わせています。非同期フロー制御に1つのアプローチを使用すると、それについて簡単に推論できます。 fetch
がPromiseを使用するため、Promiseを使用しましょう。
// Refactor getStudents and getScores to return Promise for their response bodies
function getStudents(){
return fetch(`api/students`, {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
}).then((response) => response.json())
};
function getScores(){
return fetch(`api/scores`, {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
}).then((response) => response.json())
};
// Request both students and scores in parallel and return a Promise for both values.
// `Promise.all` returns a new Promise that resolves when all of its arguments resolve.
function getStudentsAndScores(){
return Promise.all([getStudents(), getScores()])
}
// When this Promise resolves, both values will be available.
getStudentsAndScores()
.then(([students, scores]) => {
// both have loaded!
console.log(students, scores);
})
単純であるだけでなく、このアプローチは両方の要求を同時に行うため、より効率的です。あなたのアプローチは、生徒が取得されるまで待ってからスコアを取得しました。
見る - Promise.all
on MDN
関数を矢印関数でラップする必要があると思います。 promiseチェーンがコンパイルされ、イベントループに送信されるときに、関数が呼び出されます。これは競合状態を作り出しています。
function getStudentsAndScores(cbStudent, cbScores, cbStudentsScores){
getStudents(cbStudent).then(() => getScores(cbScores)).then(cbStudentsScores);
}
さらに読むためにこの記事をお勧めします: Nolan Lawsonによる約束の問題があります
そして、ここで私が作成したレポは、記事で説明した各概念の例を持っています。 ピンキースウェア
フェッチの呼び出しが完了するたびに状態を更新するのではなく、両方を完了するのを待ってから、一度に状態を更新することをお勧めします。次に、setState
callback method を使用して、次のメソッドを実行できます。
Bluebird などのPromiseライブラリを使用して、複数のフェッチリクエストが完了するのを待ってから他のことを行うことができます。
import Promise from 'bluebird'
getStudents = () => {
return fetch(`api/students`, {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
}).then(response => response.json());
};
getScores = () => {
return fetch(`api/scores`, {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
}).then(response => response.json());
};
Promise.join(getStudents(), getScores(), (students, scores) => {
this.setState({
students,
scores
}, this.rearrangeStudentsWithScores);
});