Reduxは単にグローバルな状態を称賛しただけではありませんか?


84

そのため、1週間前にReactの学習を開始しましたが、必然的に状態の問題と、コンポーネントがアプリの他の部分とどのように通信するかという問題に直面しました。探し回ったところ、Reduxが今月の味のようです。私はすべてのドキュメントを読みましたが、実際にはかなり革新的なアイデアだと思います。これが私の考えです:

州は一般的にかなり邪悪であり、プログラミングのバグの大きな原因であることに同意しています。アプリ全体に分散させるのではなく、Reduxは、変更するアクションを発行する必要があるグローバル状態ツリーにすべてを集中させないのはなぜですか?面白そう。すべてのプログラムには状態が必要なので、1つの不純なスペースに貼り付け、そこからのみ変更して、バグを簡単に追跡できるようにします。次に、個々の状態の断片をReactコンポーネントに宣言的にバインドし、それらを自動再描画させることもできます。すべてが美しいです。

ただし、このデザイン全体について2つの質問があります。まず、状態ツリーが不変である必要があるのはなぜですか?タイムトラベルのデバッグやホットリロードは気にせず、アプリに元に戻す/やり直しをすでに実装しているとします。これをしなければならないのはとても面倒に思えます:

case COMPLETE_TODO:
  return [
    ...state.slice(0, action.index),
    Object.assign({}, state[action.index], {
      completed: true
    }),
    ...state.slice(action.index + 1)
  ];

これの代わりに:

case COMPLETE_TODO:
  state[action.index].completed = true;

言うまでもなく、私は学ぶためだけにオンラインホワイトボードを作成しています。すべての状態変更は、コマンドリストにブラシストロークを追加するのと同じくらい簡単かもしれません。しばらくすると(数百のブラシストローク)、このアレイ全体を複製すると、非常に費用と時間がかかるようになる可能性があります。

アクションを介して変更されるUIから独立したグローバル状態ツリーで問題ありませんが、本当に不変である必要がありますか?このような単純な実装(非常にラフなドラフト。1分で記述)の何が問題になっていますか?

var store = { items: [] };

export function getState() {
  return store;
}

export function addTodo(text) {
  store.items.push({ "text": text, "completed", false});
}

export function completeTodo(index) {
  store.items[index].completed = true;
}

これは、発行されたアクションによって変更されたグローバル状態ツリーですが、非常にシンプルで効率的です。


2
「1つには、なぜ状態ツリーが不変である必要があるのですか?」---次に、データが変更されたかどうかを判断するためのアルゴリズムを提供する必要があります。任意のデータ構造に実装することはできません(可変の場合)。ボイラープレートを減らすために取っimmutablejsて使用return state.setIn([action.index, 'completed'], true);してください。
zerkms 2015年

1
PS:return state.map(i => i.index == action.index ? {...i, completed: true} : i);
zerkms 2015年

回答:


52

Reduxは単にグローバルな状態を称賛しただけではありませんか?

もちろん。しかし、これまでに使用したすべてのデータベースについても同じことが言えます。Reduxをメモリ内データベースとして扱うことをお勧めします-コンポーネントが反応的に依存する可能性があります。

不変性により、サブツリーが非常に効率的に変更されているかどうかをチェックできます。これは、IDチェックまで単純化されるためです。

はい、実装は効率的ですが、ツリーが何らかの方法で操作されるたびに、仮想DOM全体を再レンダリングする必要があります。

Reactを使用している場合、最終的には実際のdomとの差分を実行し、バッチ最適化された最小限の操作を実行しますが、完全なトップダウンの再レンダリングは依然として非効率的です。

不変ツリーの場合、ステートレスコンポーネントは、依存するサブツリーが以前の値と比較してIDが異なるかどうかを確認するだけでよく、そうであれば、レンダリングを完全に回避できます。


3
しかし、これは少し時期尚早な最適化ではありませんか?また、不変オブジェクトを絶えず複製するコストがDOMの再レンダリングよりも少ないことをどのようにして知ることができますか(Reactの仮想DOMはこのコストを大幅に軽減しませんか?)
Ryan Peschel 2015年

3
ええと、GUIライブラリはこの種の最適化を長い間行っています(bitquabit.com/post/the-more-things-changeを参照)。さらに、不変のデータ構造の管理は、たとえばノードの場合、思ったほどコストがかかりません。変更されると、親の単一のチェーンのみがチェーンする必要があります-残りのノードは影響を受けません。したがって、すべてのアクションでデータ構造全体を複製するわけではありません。変更されていないサブコンポーネントを再利用して、新しいデータ構造を構築します。
lorefnon 2015年

4
また、Reacts Virtual DOMは、厳密には黒魔術ではありません-React docsからの引用:「あるツリーを別のツリーに変換するための最小数の操作を生成することは、複雑でよく研究された問題です-最先端のアルゴリズムには、順序が複雑ですof O(n3)ここで、nはツリー内のノードの数です。 "
lorefnon 2015年

2
Reactが実際にはるかに優れたパフォーマンスを発揮できる理由は、次の理由によるものです。Reactはヒューリスティックに依存しているため、「安定したキーを提供しない場合(たとえば、Math.random()を使用)、すべてのサブツリーは次のようになります。毎回再レンダリングされます。ユーザーにキーを選択する選択肢を与えることで、ユーザーは自分の足を撃つことができます。」したがって、安定したキーを提供することでReactを支援できるのと同じように、不変のデータ小道具を提供することでReactを支援することができます。
lorefnon 2015年

1
ブラシストロークの配列については、以下を参照してください:facebook.github.io/immutable-js/docs /#/ Listドキュメントからの引用:リストは、JavaScript配列と同様に、インデックス付きの密集したコレクションに並べられています。リストはDequeを実装し、終了(プッシュ、ポップ)と開始(シフト解除、シフト)の両方から効率的に追加および削除します。
lorefnon 2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.