ホームページ > ウェブフロントエンド > jsチュートリアル > クロージャに巻き込まれる: React 状態管理の癖を理解する

クロージャに巻き込まれる: React 状態管理の癖を理解する

DDD
リリース: 2025-01-13 20:29:45
オリジナル
471 人が閲覧しました

Caught in a Closure: Understanding Quirks in React State Management

TLDR

  • クロージャは、関数が持ち歩くバックパックのようなもので、作成時のデータが含まれています
  • React コンポーネントはクロージャを使用して状態とプロパティを記憶します
  • 状態の更新が期待どおりに機能しない場合、クロージャが古くなるとバグが発生する可能性があります
  • 機能アップデートにより、最新の状態で動作するための信頼できるソリューションが提供されます

導入

React の状態更新が時々正しく動作しないのはなぜなのか疑問に思ったことはありますか?あるいは、ボタンを素早く複数回クリックしてもカウンターが期待どおりに更新されないのはなぜでしょうか?答えは、クロージャと React による状態更新の処理方法を理解することにあります。この記事では、すべてをピンとさせる簡単な例を使用して、これらの概念を解き明かします。

クロージャとは何ですか?

クロージャは、それが生まれた場所の小さな記憶を保持する関数であると考えてください。これは、関数が作成されたときに存在していたすべての変数のポラロイドのスナップショットのようなものです。単純なカウンターを使用してこれを実際に見てみましょう:

function createPhotoAlbum() {
    let photoCount = 0;  // This is our "snapshot" variable

    function addPhoto() {
        photoCount += 1;  // This function "remembers" photoCount
        console.log(`Photos in album: ${photoCount}`);
    }

    function getPhotoCount() {
        console.log(`Current photos: ${photoCount}`);
    }

    return { addPhoto, getPhotoCount };
}

const myAlbum = createPhotoAlbum();
myAlbum.addPhoto();     // "Photos in album: 1"
myAlbum.addPhoto();     // "Photos in album: 2"
myAlbum.getPhotoCount() // "Current photos: 2"
ログイン後にコピー
ログイン後にコピー

この例では、addPhoto 関数と getPhotoCount 関数の両方が、createPhotoAlbum の実行が終了した後でも photoCount 変数を記憶しています。これは動作中のクロージャです - 関数はその誕生地を記憶しています!

React でクロージャが重要な理由

React では、コンポーネントがその状態を記憶する方法においてクロージャが重要な役割を果たします。これは単純なカウンターコンポーネントです:

function Counter() {
    const [count, setCount] = useState(0);

    const increment = () => {
        // This function closes over 'count'
        setCount(count + 1);
    };

    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={increment}>Add One</button>
        </div>
    );
}
ログイン後にコピー

インクリメント関数は、カウント状態変数の周囲にクロージャーを形成します。これは、ボタンがクリックされたときにどの番号を追加するかを「記憶」する方法です。

問題: 古いクロージャ

ここからが興味深いところです。クロージャが予期しない動作を引き起こす可能性がある状況を作成してみましょう:

function BuggyCounter() {
    const [count, setCount] = useState(0);

    const incrementThreeTimes = () => {
        // All these updates see the same 'count' value!
        setCount(count + 1);  // count is 0
        setCount(count + 1);  // count is still 0
        setCount(count + 1);  // count is still 0!
    };

    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={incrementThreeTimes}>Add Three</button>
        </div>
    );
}
ログイン後にコピー

このボタンをクリックすると、カウントが 3 増えると思われるかもしれませんが、驚きです。 1 しか増えません。これは「古いクロージャー」が原因です。関数は、作成時の count の元の値を参照してスタックしています。

数字の 0 が表示されたホワイトボードの写真を 3 枚撮り、それぞれの写真に 1 を加えようとするようなものだと考えてください。各写真にはまだ 0 が含まれています!

解決策: 機能アップデート

React はこの問題に対する洗練された解決策を提供します - 機能アップデート:

function FixedCounter() {
    const [count, setCount] = useState(0);

    const incrementThreeTimes = () => {
        // Each update builds on the previous one
        setCount(current => current + 1);  // 0 -> 1
        setCount(current => current + 1);  // 1 -> 2
        setCount(current => current + 1);  // 2 -> 3
    };

    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={incrementThreeTimes}>Add Three</button>
        </div>
    );
}
ログイン後にコピー

クロージャーの値を使用する代わりに、React に「現在の値を取得してそれに 1 を追加する」ように指示します。それは、ホワイトボードに追加する前に常にホワイトボード上の現在の番号を確認する、親切なアシスタントがいるようなものです!

現実世界の例: ソーシャルメディアの「いいね!」ボタン

これが現実世界のシナリオ、つまりソーシャル メディア投稿の「いいね!」ボタンにどのように適用されるかを見てみましょう:

function createPhotoAlbum() {
    let photoCount = 0;  // This is our "snapshot" variable

    function addPhoto() {
        photoCount += 1;  // This function "remembers" photoCount
        console.log(`Photos in album: ${photoCount}`);
    }

    function getPhotoCount() {
        console.log(`Current photos: ${photoCount}`);
    }

    return { addPhoto, getPhotoCount };
}

const myAlbum = createPhotoAlbum();
myAlbum.addPhoto();     // "Photos in album: 1"
myAlbum.addPhoto();     // "Photos in album: 2"
myAlbum.getPhotoCount() // "Current photos: 2"
ログイン後にコピー
ログイン後にコピー

結論

重要なポイント

  1. クロージャは、メモリを持つ関数と同様に、変数が作成された場所から変数を記憶する関数です。
  2. 古いクロージャは、関数が現在の値ではなくメモリからの古い値を使用している場合に発生します。
  3. React の 機能更新 (setCount(count => count 1)) により、常に最新の状態で作業できるようになります。

覚えておいてください: 以前の値に基づいて状態を更新するときは、機能的な更新を優先してください。これは、記憶に基づいて作業するのではなく、変更を加える前に常に現在の値をチェックしてくれる信頼できるアシスタントがいるようなものです!

ベストプラクティス

  • 新しい状態が以前の状態に依存する場合は、機能更新を使用します
  • 非同期操作とイベント ハンドラーのクロージャには特に注意してください
  • 疑わしい場合は、値を console.log に記録して、古いクロージャがないか確認してください
  • 状態の更新をデバッグするには、React DevTools の使用を検討してください

これらの概念を理解すれば、React での状態更新をプロのように処理できるようになります。コーディングを楽しんでください! ?

以上がクロージャに巻き込まれる: React 状態管理の癖を理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート