フックを学ぼうとしているのですが、useState
メソッドが混乱しています。配列の形式で状態に初期値を割り当てています。useState
スプレッド構文の有無にかかわらず、set メソッドが機能しません。
別の PC 上に API を作成し、それを呼び出して、状態に設定したいデータを取得しています。
これが私のコードです:
<div id="root"></div>
<script type="text/babel" defer>
// import React, { useState, useEffect } from "react";
// import ReactDOM from "react-dom";
const { useState, useEffect } = React; // web-browser variant
const StateSelector = () => {
const initialValue = [
{
category: "",
photo: "",
description: "",
id: 0,
name: "",
rating: 0
}
];
const [movies, setMovies] = useState(initialValue);
useEffect(() => {
(async function() {
try {
// const response = await fetch("http://192.168.1.164:5000/movies/display");
// const json = await response.json();
// const result = json.data.result;
const result = [
{
category: "cat1",
description: "desc1",
id: "1546514491119",
name: "randomname2",
photo: null,
rating: "3"
},
{
category: "cat2",
description: "desc1",
id: "1546837819818",
name: "randomname1",
rating: "5"
}
];
console.log("result =", result);
setMovies(result);
console.log("movies =", movies);
} catch (e) {
console.error(e);
}
})();
}, []);
return <p>hello</p>;
};
const rootElement = document.getElementById("root");
ReactDOM.render(<StateSelector />, rootElement);
</script>
<script src="https://unpkg.com/@babel/standalone@7/babel.min.js"></script>
<script src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
どちらも機能しませsetMovies(result)
んsetMovies(...result)
。
result
変数が配列にプッシュされることを期待していますmovies
。
ベストアンサー1
多くの.setState()
クラスコンポーネントのようにReact.Component
またはを拡張して作成された場合React.PureComponent
、フックが提供するアップデータを使用した状態の更新useState
も非同期であり、すぐには反映されません。
また、ここでの主な問題は、非同期の性質だけではなく、状態値が関数の現在のクロージャに基づいて使用され、状態の更新が次の再レンダリングに反映され、既存のクロージャは影響を受けず、新しいクロージャが作成されるという事実です。現在の状態では、フック内の値は既存のクロージャによって取得され、再レンダリングが発生すると、関数が再度作成されたかどうかに基づいてクロージャが更新されます。
関数を追加したとしてもsetTimeout
、再レンダリングが行われるまでの時間が経過するとタイムアウトが実行されますが、 はsetTimeout
更新された値ではなく、前回のクロージャからの値を使用します。
setMovies(result);
console.log(movies) // movies here will not be updated
状態の更新時にアクションを実行したい場合は、クラスコンポーネントでuseEffect
使用するのと同じようにフックを使用する必要があります。これcomponentDidUpdate
は、返されるセッターにuseState
コールバックパターンがないためです。
useEffect(() => {
// action on update of movies
}, [movies]);
状態を更新するための構文に関しては、状態内のsetMovies(result)
以前の値を非同期リクエストから取得できる値に置き換えます。movies
ただし、レスポンスを既存の値とマージする場合は、状態更新のコールバック構文と、スプレッド構文の正しい使用法を使用する必要があります。
setMovies(prevMovies => ([...prevMovies, ...result]));