如何添加/删除使用normalizr生成的redux存储?

m0m*_*eni 36 javascript reactjs redux normalizr

查看自述文件中的示例:

鉴于"坏"结构:

[{
  id: 1,
  title: 'Some Article',
  author: {
    id: 1,
    name: 'Dan'
  }
}, {
  id: 2,
  title: 'Other Article',
  author: {
    id: 1,
    name: 'Dan'
  }
}]
Run Code Online (Sandbox Code Playgroud)

添加新对象非常容易.我所要做的就是这样

return {
  ...state,
  myNewObject
}
Run Code Online (Sandbox Code Playgroud)

在减速机中.

现在给出了"好"树的结构,我不知道应该如何处理它.

{
  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'
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我想到的每一种方法都需要一些复杂的对象操作,这让我觉得我没有走上正确的轨道,因为普通人应该让我的生活变得更轻松.

我找不到任何以这种方式使用normalizr树的人在线的例子.官方的例子没有添加和删除所以它也没有任何帮助.

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

m0m*_*eni 34

从后由终极版/ normalizr创建者下面直接是在这里:

所以你的州看起来像:

{
  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]
}
Run Code Online (Sandbox Code Playgroud)

你的减速器可能看起来像

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
});
Run Code Online (Sandbox Code Playgroud)

那么这里发生了什么?首先,请注意状态是规范化的.我们从未在其他实体内部拥有实体.相反,它们通过ID互相引用.因此,每当某个对象发生变化时,只有一个地方需要更新.

其次,注意我们如何通过在计划缩减器中添加适当的实体并将其ID添加到currentPlans reducer来对CREATE_PLAN做出反应.这个很重要.在更复杂的应用程序中,您可能有关系,例如,计划reducer可以通过在计划内的数组中附加新ID来以相同的方式处理ADD_EXERCISE_TO_PLAN.但是如果练习本身已经更新,那么计划缩减器就不需要知道,因为ID没有改变.

第三,注意实体减少者(计划和练习)有特殊条款,注意行动.这是因为我们有一个"已知真相"的服务器响应,我们想要更新我们要反映的所有实体.要在分派操作之前以这种方式准备数据,可以使用normalizr.您可以在Redux仓库中的"真实世界"示例中看到它.

最后,请注意实体减速器是如何相似的.您可能想要编写一个函数来生成它们.这超出了我的答案范围 - 有时你需要更多的灵活性,有时你想要更少的样板.您可以查看"真实世界"示例缩减器中的分页代码,以获取生成类似缩减器的示例.

哦,我用{... a,... b}语法.它在Babel阶段2中作为ES7提议启用.它被称为"对象扩展运算符",相当于编写Object.assign({},a,b).

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

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)
    ]
  };
Run Code Online (Sandbox Code Playgroud)

可写成

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)
  };
Run Code Online (Sandbox Code Playgroud)

  • @NikSo这正是我在这里的原因.....我在哪里看到没有提到从标准化商店中删除实体的自动方式?我发现很难相信我们是唯一的......你是否已经触底了? (6认同)
  • 很好的解释!那你怎么删除?{... state,[action.id]:undefined}? (5认同)