React アプリの状態管理は、動的で応答性の高いユーザー インターフェイスを作成する上で重要な部分です。従来、開発者は、必要な変更を加えた状態の新しいコピーを生成する不変の更新に依存していました。この方法は予測可能性を提供し、デバッグを容易にしますが、特に大規模または複雑なデータ構造を扱う場合、パフォーマンスが低下する可能性があります。
この記事では、状態を処理するための 2 つの一般的な React フレームワークについて説明します。 React Mutative と Immer。どちらのライブラリも、異なる手段を通じてではありますが、不変性を促進します。
Mutative の実装は Immer の実装と非常に似ていますが、より堅牢です。 Mutative は、Immer やネイティブ Reducer よりも効率的にデータを処理します。 Mutative チームによると、この状態管理ソリューションにより、不変の更新が容易になります。これは、平均的な手作り減速機よりも約 2 ~ 6 倍高速であり、Immer よりも 10 倍以上高速です。
Mutative.js の利点をいくつか示します:
たとえば、リストを含む状態オブジェクトがあるとします。リストの最後の項目を完了としてマークし、新しい項目を追加する予定です:
const state = { list: [ { text: 'Learn JavaScript', done: true }, { text: 'Learn React', done: true }, { text: 'Learn Redux', done: false }, ], };
定期的な不変データ更新を使用する場合は、次のように記述できます:
const nextState = { ...state, list: [ ...state.list.slice(0, 2), { ...state.list[2], done: true, }, { text: 'Learn Mutative', done: true }, ], };
しかし、Mutative を使用するときは、次のように書くことができます:
import { create } from 'mutative'; const nextState = create(state, (draft) => { draft.list[2].done = true; draft.list.push({ text: 'Learn Mutative', done: true }); });
これは Mutative の基本的な使用法であり、不変の更新をより簡単に実装できるようになります。
ドイツ語で「常に」を意味する Immer は、不変状態の操作をより便利にする小さなパッケージです。 2019 JavaScript オープンソース賞「最も影響力のある貢献」を受賞。
これらの利点は、オブジェクト、配列、またはマップのプロパティを変更するのではなく、常に編集済みのコピーを作成することによって得られる傾向があります。これにより、コードの作成が非常に困難になる可能性があり、そのような制限を意図せずに破ってしまう可能性があります。これらの問題の解決を通じて、Immer は不変データのアプローチを順守できるよう支援します。 React Immer の利点をいくつか示します:
Immer は、意図しない突然変異を検出した場合にエラーを報告します。
Immer は、不変オブジェクトに深い変更を作成するときに必要な慣例的な定型コードの要件を排除します。 Immer を使用しない場合、オブジェクトの複製はすべてのレベルで手動で作成する必要があります。通常は、多数のスプレッド操作を実行することによって行われます。 Immer を利用すると、ドラフト オブジェクトに変更が加えられ、元のオブジェクトを変更せずに変更が記録され、適切な複製が作成されます。
Immer では、パラダイムから利益を得るために特定の API やデータ構造を習得する必要はありません。 Immer を使用すると、安全性を保ちながら、プレーンな JavaScript データ構造やよく知られている変更可能な JavaScript API にアクセスできます。
以下は簡単な比較のための簡単な例です:
const baseState = [ { title: "Learn JavaScript", done: true }, { title: "Try Immer", done: false } ]
前の基本状態があり、2 番目の ToDo を更新して 3 番目の ToDo を追加する必要があると仮定します。ただし、元の BaseState を変更したくなく、(最初の ToDo を維持するため) 深いクローン作成を避けます。
Immer を使用しない場合、不変性を維持するには、影響を受ける状態オブジェクトのすべてのレベルをコピーする必要があります。
const nextState = baseState.slice() // shallow clone the array nextState[1] = { // replace element 1... ...nextState[1], // with a shallow clone of element 1 done: true // ...combined with the desired update } //Since nextState was freshly cloned, using push is safe here, // but doing the same thing at any arbitrary time in the future would // violate the immutability principles and introduce a bug! nextState.push({title: "Tweet about it"})
Immer はこのプロセスを簡素化します。生成関数を使用できます。この関数は、最初の引数として開始したい状態を受け取り、2 番目のパラメーターとしてレシピと呼ばれる関数を受け取ります。この関数には、簡単な変更を適用できるドラフトが渡されます。レシピが完了すると、突然変異が記録され、次の状態を作成するために使用されます。 generate は、必要なコピーをすべて処理しながら、データを凍結することで将来の意図しない変更からデータを保護します。
import {produce} from "immer" const nextState = produce(baseState, draft => { draft[1].done = true draft.push({title: "Tweet about it"}) })
React を備えた Immer をお探しですか? React + Immer の Web サイトに直接アクセスしてください。
Mutative と Immer はどちらも概念的には同様の方法で不変の更新を実現しますが、パフォーマンスに影響する重要な実装の違いがあります。内訳は次のとおりです:
Secret Sauce: This speed advantage boils down to how each library creates the final immutable state object. Mutative employs a highly optimized algorithm that efficiently builds a new data structure reflecting the changes you made in the draft, prioritizing raw speed.
Immer's Overhead: Immer, on the other hand, utilizes a proxy object to track mutations on the draft state. This approach offers more flexibility but comes with an overhead that can significantly slow things down, particularly when dealing with large datasets. It's like adding an extra step in the process.
Auto-Freeze and the Tradeoff: Immer offers an optional feature called auto-freeze, which helps prevent accidental modifications to the original state. This is great for safety, but it comes at a performance cost. Disabling auto-freeze can bring Immer closer to Mutative's speed, but then you lose the safety net.
Both Mutative and Immer offer an intuitive way to write state updates that appear to mutate the state but ultimately result in immutable updates. However, there are some differences in syntax and potential for errors:
Syntax Mutative: Leverages familiar syntax that resembles traditional mutations. You write code as if you're directly modifying the state object.
Example:
const draft = createDraft(currentState); draft.todos.push({ text: 'Buy milk' }); const newState = commit(draft);
Immer Syntax: Requires using specific Immer functions like produce to wrap your update logic.
Example:
const newState = produce(currentState, draft => { draft.todos.push({ text: 'Buy milk' }); });
Draft escapes occur when you unintentionally modify the original state object instead of the draft copy in libraries like Mutative and Immer.
Mutative: While Mutative's syntax might feel familiar, there's a higher risk of accidentally modifying the original state object (draft escapes). This can happen if you forget to use the commit function to finalize the changes and create the new state. It requires stricter discipline to ensure all modifications go through the draft.
Immer: Immer's syntax explicitly forces you to work within the draft state using functions like produce. This reduces the chance of accidentally modifying the original state, making it inherently safer.
Ultimately, the best choice depends on your specific project requirements and team preferences. Consider trying both libraries on a small project to see which one feels more comfortable for your developers.
以上がReact Mutative と React Immer の比較の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。