17

この状態構造を持つ redux ストアがあるとします。

{
  items: {
    "id1" : {
      foo: "foo1",
      bar: "bar1"
    },
    "id2": {
      foo: "foo2",
      bar: "bar2"
    } 
  }
}

このストアは、アイテムのまったく新しい価値を受け取ることによって進化します。

const reduceItems = function(items = {}, action) {
  if (action.type === 'RECEIVE_ITEM') {
    return {
      ...items,
      [action.payload.id]: action.payload,
    };
  }
  return items;
};

状態の一部のみを抽出する SubItem ビューのリストをレンダリングするルート ビューを表示したいと考えています。たとえば、SubItem ビューは foos のみを考慮し、それを取得する必要があります。

function SubItem({ id, foo }) {
  return <div key={id}>{foo}</div>
}

私は状態の「サブパート」のみを気にするので、それを「ダム」ルート ビューに渡したいと思います。

const Root = function({ subitems }) {
  // subitems[0] => { id: 'id1', foo: "foo1" }
  // subitems[1] => { id; 'id2', foo : "foo2" }
  const children = subitems.map(SubItem);
  return <div>{children}</div>;
};

このコンポーネントを簡単に接続して、状態の変更をサブスクライブできます。

function mapStatesToProps(state) {    
 return {
    subitems: xxxSelectSubItems(state)
 }
}
return connect(mapStatesToProps)(Root)

私の根本的な問題は、私が気にしない状態の部分 ( bar) が変化するとどうなるかということです。fooまたは、どちらもbar変更されていないアイテムの新しい値を受け取った場合でも、次のようになります。

setInterval(() => {
    store.dispatch({
      type: 'RECEIVE_ITEM',
      payload: {
        id: 'id1',
        foo: 'foo1',
        bar: 'bar1',
      },
    });
  }, 1000);

「素朴な」セレクターの実装を使用する場合:

// naive version
function toSubItem(id, item) {
  const foo = item.foo;
  return { id, foo };
}

function dumbSelectSubItems(state) {
  const ids = Object.keys(state.items);
  return ids.map(id => {
    const item = state.items[id];
    return toSubItem(id, item);
  });
}

次に、リストは呼び出されるたびに完全に新しいオブジェクトになり、私のコンポーネントは毎回レンダリングされます。

もちろん、接続されたコンポーネントが純粋であるため、常に同じリストを返す「定数」セレクターを使用すると、再レンダリングされます (ただし、これは、接続されたコンポーネントが純粋であることを示すためのものです)。

// fully pure implementation
const SUBITEMS = [
  {
    id: 'id0',
    foo: 'foo0',
  },
];
function constSelectSubItems(state) {
  return SUBITEMS;
}

リストが変更されているが同じ要素が含まれている「almostConst」バージョンを使用すると、これは少しトリッキーになります。

const SUBITEM = {
  id: 'id0',
  foo: 'foo0',
};
function almostConstSelectSubItems(state) {
  return [SUBITEM];
}

予想通り、リストが異なるため、内部のアイテムは同じですが、コンポーネントは毎秒再レンダリングされます。

これは、「再選択」が役立つ可能性がある場所ですが、ポイントを完全に見逃していないかどうか疑問に思っています。私はreselectこれを使って振る舞うことができます:

const reselectSelectIds = (state, props) => Object.keys(state.items);
const reselectSelectItems = (state, props) => state.items;
const reselectSelectSubItems = createSelector([reSelectIds, reSelectItems], (ids, items) => {
  return ids.map(id => toSubItem(id, items));
});

しかし、その後はナイーブ バージョンとまったく同じように動作します。

そう:

  • 配列をメモ化しようとするのは無意味ですか?
  • これを再選択できますか?
  • 州の組織を変更する必要がありますか?
  • 「deepEqual」テストを使用して、ルートに shouldComponentUpdate を実装する必要がありますか?
  • Root が接続コンポーネントであることをあきらめて、各 LeafItems を接続コンポーネント自体にする必要がありますか?
  • immutable.js は役に立ちますか?
  • Reactはスマートで、仮想DOMが計算されると何も再描画しないため、実際には問題ではありません?

私が彼の無意味なことをしようとしている可能性があり、私のreduxストアに問題が隠されている可能性があるので、明らかなエラーを遠慮なく述べてください.

4

1 に答える 1