[解決済み] Reactフック:コールバック内から最新の状態にアクセスする
質問
編集 (2020年6月22日): この質問に対する関心が再燃しているため、いくつかの点で混乱があることに気づきました。そこで、強調したいのは、問題の例はおもちゃの例として意図されていることです。この問題を反映しているわけではありません。この質問につながった問題は、サードパーティのライブラリ(コントロールが限られています)を使用して、関数の引数としてコールバックを取るというものです。そのコールバックに最新の状態を提供する正しい方法は何でしょうか。reactクラスでは、これは
this
. Reactフックでは、ステートが
React.useState()
の関数にカプセル化されているため、もしコールバック
を取得します。
を通して状態を取得します。
React.useState()
を通して取得する場合、それは古い値 (コールバックがセットアップされたときの値) になります。しかし、もし
が設定されると
を設定すると、渡された引数を通じて最新の状態にアクセスできるようになります。つまり、このようなコールバックでReactフックを使って最新の状態を取得できる可能性があるのは、次のような方法です。
設定
を設定することで最新の状態を取得できる可能性があります。これは動作しますが、直感に反しています。
-- 元の質問は以下に続きます。
Reactフックを使用しており、コールバック内から状態を読み取ろうとしています。コールバックがそれにアクセスするたびに、デフォルトの値に戻ります。
以下のようなコードで。コンソールに表示され続ける
Count is: 0
を何度クリックしても表示されません。
function Card(title) {
const [count, setCount] = React.useState(0)
const [callbackSetup, setCallbackSetup] = React.useState(false)
function setupConsoleCallback(callback) {
console.log("Setting up callback")
setInterval(callback, 3000)
}
function clickHandler() {
setCount(count+1);
if (!callbackSetup) {
setupConsoleCallback(() => {console.log(`Count is: ${count}`)})
setCallbackSetup(true)
}
}
return (<div>
Active count {count} <br/>
<button onClick={clickHandler}>Increment</button>
</div>);
}
const el = document.querySelector("#root");
ReactDOM.render(<Card title='Example Component' />, el);
次のようなコードがあります。 はこちら
コールバック内で状態を設定するのは問題ありませんが、最新の状態にアクセスすることだけが問題でした。
推測するに、状態を変更するとCard関数の新しいインスタンスが作成されるのではと思います。そして、コールバックは古いものを参照しています。以下のドキュメントに基づくと https://reactjs.org/docs/hooks-reference.html#functional-updates のドキュメントに基づき、私は、コールバック内で setState を呼び出し、setState に関数を渡して、setState 内から現在の状態にアクセスできるかどうかを確認するというアプローチを取ることを思いつきました。置き換える
setupConsoleCallback(() => {console.log(`Count is: ${count}`)})
で
setupConsoleCallback(() => {setCount(prevCount => {console.log(`Count is: ${prevCount}`); return prevCount})})
次のようなコードがあります。 はこちら
このアプローチもうまくいきませんでした。 編集部:実はその2つ目のアプローチ は が動作します。私のコールバックにタイプミスがあっただけです。これは正しいアプローチです。以前の状態にアクセスするために、setStateを呼び出す必要があります。状態を設定するつもりがないのに。
Reactのクラスで似たようなアプローチを取った気がしますが コードの一貫性を考えると、React Effectsにこだわる必要がありますね。
コールバック内から最新の状態情報にアクセスするにはどうしたらいいですか?
どのように解決するのですか?
あなたのシナリオ (新しいコールバックを作成してサードパーティ ライブラリに渡し続けることができない場合) に対しては
useRef
を使って、現在の状態を持つミュータブルオブジェクトを保持することができます。 このように。
function Card(title) {
const [count, setCount] = React.useState(0)
const [callbackSetup, setCallbackSetup] = React.useState(false)
const stateRef = useRef();
// make stateRef always have the current count
// your "fixed" callbacks can refer to this object whenever
// they need the current value. Note: the callbacks will not
// be reactive - they will not re-run the instant state changes,
// but they *will* see the current value whenever they do run
stateRef.current = count;
function setupConsoleCallback(callback) {
console.log("Setting up callback")
setInterval(callback, 3000)
}
function clickHandler() {
setCount(count+1);
if (!callbackSetup) {
setupConsoleCallback(() => {console.log(`Count is: ${stateRef.current}`)})
setCallbackSetup(true)
}
}
return (<div>
Active count {count} <br/>
<button onClick={clickHandler}>Increment</button>
</div>);
}
コールバックはミュータブルオブジェクトを参照して、現在の状態を読み取ることができます。 これはクロージャでミュータブルオブジェクトをキャプチャし、レンダリングごとにミュータブルオブジェクトは現在の状態の値で更新されます。
関連
-
Vue Element-uiは、アイコンを追加するためのツリーコントロールノードを詳細に実装しています。
-
JavaScriptの配列共通メソッド解説
-
vue ディレクティブ v-html と v-text
-
[解決済み] 配列の結合時に未定義のプロパティ 'push' を読み込むことができない
-
[解決済み】(Google Map API) Geocodeは以下の理由で成功しませんでした。REQUEST_DENIED
-
[解決済み】エラー。Ionic使用中にモジュール '../lib/utils/unsupported.js' が見つかりませんでした。
-
[解決済み] Reactのstateとpropsの違いとは?
-
[解決済み] React HooksでcomponentWillMount()を使用するには?
-
[解決済み】react hooksで`setState`コールバックを使用する方法
-
[解決済み] react-hooksによるステート更新時の非同期コードの実行
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
JavaScriptの関数この指摘の問題を説明
-
Vue Element-uiは、アイコンを追加するためのツリーコントロールノードを詳細に実装しています。
-
Vueでルートネスティングを実装する例
-
[解決済み】ローカルファイルを開くことができません - Chrome: ローカルリソースの読み込みが許可されていない
-
[解決済み】Node.jsで "Cannot find module "エラーを解決するには?
-
[解決済み】React - TypeError: 未定義のプロパティ 'props' を読み取ることができない。
-
[解決済み】ExpressJS : res.redirect()が期待通りに動かない?
-
フロントエンド非同期(アシンク)ソリューション(全ソリューション)
-
JavaScriptのgetElementById()メソッド入門
-
jq は html ページとデータを動的に分割する。