11

サーバーからの応答を正規化するために normalizr で redux を使用します。基本的には実際の例に従います。この方法entitiesのレデューサーは非常に単純で、応答をマージするだけです。私が今抱えている問題は、一種のdelete操作です。このissue#21 の normalizr リポジトリを見つけましたが、これを解決する方法がわかりませんでした。例えば、

現在の状態は

{
  entities:
    product_categories: {
      ...
      13: {
        ...
        products: ["1", "2"], <--------------- [i] Current state
        ...
      }
    },
    products: {
      1: {
        id: "1"
      }
    }
}

正規化された応答は

{
  ...
    product_categories: {
      ...
      13: {
        ...
        products: ["1"], <---------------- [2] Normalized result
      }
  ...
}

ご覧のとおり、バックエンド API は、このカテゴリに属する​​すべての製品 ID を返します。この場合、「2」は切り離されています。「entities」レデューサーがこの応答をマージすると、「2」がまだぶらぶらしています。今はページをリロードするだけですが、このケースを処理するためのより良い方法があるかどうか疑問に思っていますか?

レデューサーではentities、実際の例のようにマージするだけです。

return merge({}, state, action.payload.entities);

4

3 に答える 3

11

そこにあることを心配しないでください。あなたの状態をデータベースと考えてください。複雑なカスケードを避けるために、データベースからレコードを完全に削除するわけではありません。通常は、データベース内のステータスを変更するだけです。同様に、Normalizer を使用すると、エンティティを完全に削除するのではなく、ユーザーがページを離れるまでエンティティをキャッシュに残します。

于 2015-11-18T23:27:06.807 に答える
0

以下は、私のソリューションの説明とそれに続くコードです。

削除を実行するために、削除アクションを処理するようにレデューサーを更新しました: REMOVE_ENTITY_ITEM. アクションでは、削除するエンティティのidandを渡します。name

レデューサーでは、最初に にあるエンティティ自体を削除しstore.entities[entityName][entityId]ます。次に、idそれを参照している可能性のある他のすべてのエンティティから削除する必要があります。私はnormalizrすべてのエンティティを使用しているので、フラットであり、それらが別のエンティティを参照している場合、それらはその ID のみを配列に持っています。これにより、参照を比較的簡単に削除できます。すべてのエンティティをループして、削除されるエンティティへの参照を除外するだけです。

このアプローチは、他の 2 つのアプローチ (#1.) アプリ/状態の更新、#2.) エンティティのステータス ビットを反転することと組み合わせて使用​​します。UI でオフになっているアイテムを削除してからフィルタリングするのではありません。これらのアプローチはここでよく議論されています

const entities = (state={}, action) => {
  if(action.payload && action.payload.entities) {
    return merge( {} , state, action.payload.entities);
  }else{
    return deleteHandlingReducer(state, action)
  }
}

const deleteHandlingReducer = (state=initialSate, action) => {
  switch(action.type){
    case "REMOVE_ENTITY_ITEM":
      if (!action.meta || !action.meta.name || !action.meta.id) {
        return state;
      }else{
        let newState = Object.assign({}, state);
        if(newState[action.meta.name]){
          delete newState[action.meta.name][action.meta.id];
          Object.keys(state).map(key => {
            let entityHash = state[key];
            Object.keys(entityHash).map(entityId => {
              let entity = entityHash[entityId];
              if(entity[action.meta.name] &&
                Array.isArray(entity[action.meta.name])){
                  entity[action.meta.name] = entity[action.meta.name].
                    filter(item => item != action.meta.id)
              }
            });
          })
        }
        return newState;
      }
    default:
      return state;
  }
}

削除するには、次のようなアクションを実行します。

store.dispatch({
  type: "REMOVE_ENTITY_ITEM",
  meta: {
    id: 1,
    name: "job_titles"
  }
});
于 2016-11-14T16:02:50.490 に答える