如何添加/删除由normalizr生成的redux存储? [英] How do you add/remove to a redux store generated with normalizr?

查看:92
本文介绍了如何添加/删除由normalizr生成的redux存储?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

自述文件中查找示例:

给出不良"结构:

[{
  id: 1,
  title: 'Some Article',
  author: {
    id: 1,
    name: 'Dan'
  }
}, {
  id: 2,
  title: 'Other Article',
  author: {
    id: 1,
    name: 'Dan'
  }
}]

添加新对象非常容易.我要做的只是像

It's extremely easy to add a new object. All I have to do is something like

return {
  ...state,
  myNewObject
}

在减速器中.

现在,鉴于好"树的结构,我不知道该如何处理.

Now given the structure of the "good" tree, I have no idea how I should approach it.

{
  result: [1, 2],
  entities: {
    articles: {
      1: {
        id: 1,
        title: 'Some Article',
        author: 1
      },
      2: {
        id: 2,
        title: 'Other Article',
        author: 1
      }
    },
    users: {
      1: {
        id: 1,
        name: 'Dan'
      }
    }
  }
}

我想到的每种方法都需要进行一些复杂的对象操作,这使我感到自己处在不正确的轨道上,因为normalizr应该会使我的生活更轻松.

Every approach I've thought of requires some complex object manipulation, which makes me feel like I'm not on the right track because normalizr is supposed to be making my life easier.

我找不到任何以这种方式使用normalizr树的人的在线示例. 官方示例不会添加和删除,因此也无济于事.

I can't find any examples online of someone working with the normalizr tree in this way. The official example does no adding and removing so it was no help either.

有人可以让我知道如何以正确的方式从normalizr树中添加/删除吗?

Could someone let me know how to add/remove from a normalizr tree the right way?

推荐答案

以下内容直接来自redux/normalizr创建者的帖子此处:

The following is directly from a post by the redux/normalizr creator here:

所以您的状态如下:

{
  entities: {
    plans: {
      1: {title: 'A', exercises: [1, 2, 3]},
      2: {title: 'B', exercises: [5, 1, 2]}
     },
    exercises: {
      1: {title: 'exe1'},
      2: {title: 'exe2'},
      3: {title: 'exe3'}
    }
  },
  currentPlans: [1, 2]
}

您的减速器可能看起来像

Your reducers might look like

import merge from 'lodash/object/merge';

const exercises = (state = {}, action) => {
  switch (action.type) {
  case 'CREATE_EXERCISE':
    return {
      ...state,
      [action.id]: {
        ...action.exercise
      }
    };
  case 'UPDATE_EXERCISE':
    return {
      ...state,
      [action.id]: {
        ...state[action.id],
        ...action.exercise
      }
    };
  default:
    if (action.entities && action.entities.exercises) {
      return merge({}, state, action.entities.exercises);
    }
    return state;
  }
}

const plans = (state = {}, action) => {
  switch (action.type) {
  case 'CREATE_PLAN':
    return {
      ...state,
      [action.id]: {
        ...action.plan
      }
    };
  case 'UPDATE_PLAN':
    return {
      ...state,
      [action.id]: {
        ...state[action.id],
        ...action.plan
      }
    };
  default:
    if (action.entities && action.entities.plans) {
      return merge({}, state, action.entities.plans);
    }
    return state;
  }
}

const entities = combineReducers({
  plans,
  exercises
});

const currentPlans = (state = [], action) {
  switch (action.type) {
  case 'CREATE_PLAN':
    return [...state, action.id];
  default:
    return state;
  }
}

const reducer = combineReducers({
  entities,
  currentPlans
});

那么这是怎么回事?首先,请注意状态已归一化.我们再也没有其他实体内部的实体.相反,它们通过ID相互引用.因此,只要某些对象发生更改,就只有一个地方需要更新.

So what's going on here? First, note that the state is normalized. We never have entities inside other entities. Instead, they refer to each other by IDs. So whenever some object changes, there is just a single place where it needs to be updated.

第二,请注意我们如何通过在计划缩减器中添加适当的实体并将其ID添加到currentPlans缩减器中来对CREATE_PLAN做出反应.这个很重要.在更复杂的应用中,您可能会有关系,例如计划精简程序可以通过将新的ID附加到计划内的数组来以相同的方式处理ADD_EXERCISE_TO_PLAN.但是,如果演练本身进行了更新,则由于ID尚未更改,因此计划还原器无需知道这一点.

Second, notice how we react to CREATE_PLAN by both adding an appropriate entity in the plans reducer and by adding its ID to the currentPlans reducer. This is important. In more complex apps, you may have relationships, e.g. plans reducer can handle ADD_EXERCISE_TO_PLAN in the same way by appending a new ID to the array inside the plan. But if the exercise itself is updated, there is no need for plans reducer to know that, as ID has not changed.

第三,请注意,实体化简(计划和练习)具有特殊的条款,当心action.entities.如果我们有一个带有已知事实"的服务器响应,我们想更新所有实体以反映出来.要在分派操作之前以这种方式准备数据,可以使用normalizr.您可以在Redux repo的真实世界"示例中看到它.

Third, notice that the entities reducers (plans and exercises) have special clauses watching out for action.entities. This is in case we have a server response with "known truth" that we want to update all our entities to reflect. To prepare your data in this way before dispatching an action, you can use normalizr. You can see it used in the "real world" example in Redux repo.

最后,请注意实体化简器是如何相似的.您可能要编写一个函数来生成这些函数.这超出了我的答案范围,有时您需要更大的灵活性,有时您需要更少的样板.您可以在真实世界"示例化例中查看分页代码,以生成类似的化例.

Finally, notice how entities reducers are similar. You might want to write a function to generate those. It's out of scope of my answer—sometimes you want more flexibility, and sometimes you want less boilerplate. You can check out pagination code in "real world" example reducers for an example of generating similar reducers.

哦,我使用了{... a,... b}语法.它已在Babel第2阶段作为ES7提案启用.它称为对象散布算子",等效于编写Object.assign({},a,b).

Oh, and I used { ...a, ...b } syntax. It's enabled in Babel stage 2 as ES7 proposal. It's called "object spread operator" and equivalent to writing Object.assign({}, a, b).

对于库,您可以使用Lodash(请注意不要突变,例如merge({},a,b}是正确的,但merge(a,b)不正确),updeep,react-addons-update或其他的东西.但是,如果您发现自己需要进行深层更新,则可能意味着状态树不够平坦,并且您没有充分利用功能组合.甚至您的第一个示例:

As for libraries, you can use Lodash (be careful not to mutate though, e.g. merge({}, a, b} is correct but merge(a, b) is not), updeep, react-addons-update or something else. However if you find yourself needing to do deep updates, it probably means your state tree is not flat enough, and that you don't utilize functional composition enough. Even your first example:

case 'UPDATE_PLAN':
  return {
    ...state,
    plans: [
      ...state.plans.slice(0, action.idx),
      Object.assign({}, state.plans[action.idx], action.plan),
      ...state.plans.slice(action.idx + 1)
    ]
  };

可以写为

const plan = (state = {}, action) => {
  switch (action.type) {
  case 'UPDATE_PLAN':
    return Object.assign({}, state, action.plan);
  default:
    return state;
  }
}

const plans = (state = [], action) => {
  if (typeof action.idx === 'undefined') {
    return state;
  }
  return [
    ...state.slice(0, action.idx),
    plan(state[action.idx], action),
    ...state.slice(action.idx + 1)
  ];
};

// somewhere
case 'UPDATE_PLAN':
  return {
    ...state,
    plans: plans(state.plans, action)
  };

这篇关于如何添加/删除由normalizr生成的redux存储?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆