在 redux reducer 中更新状态的正确方法 [英] Right way to update state in redux reducers

查看:32
本文介绍了在 redux reducer 中更新状态的正确方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是 redux 和 es6 语法的新手.我使用官方 redux 教程制作我的应用程序,并使用这个 example.

I'm a newbie in redux and es6 syntax. I make my app with official redux tutorial, and with this example.

下面有JS代码段.我的观点 - 在帖子减速器中定义 REQUEST_POST_BODY 和 RECEIVE_POST_BODY 案例.主要难点 - 在商店中找到并更新正确的对象.

There is JS snippet below. My point - to define REQUEST_POST_BODY and RECEIVE_POST_BODY cases in posts reducer. Main difficult - to find and update right object in store.

我尝试使用示例中的代码:

I try to use code from example:

  return Object.assign({}, state, {
    [action.subreddit]: posts(state[action.subreddit], action)
  })

但它使用了简单的帖子数组.不需要通过 id 找到正确的帖子.

But it used simple array of posts. It's not needed to find right post by id.

这是我的代码:

  const initialState = {
    items: [{id:3, title: '1984', isFetching:false}, {id:6, title: 'Mouse', isFetching:false}]
  }

  // Reducer for posts store
  export default function posts(state = initialState, action) {
    switch (action.type) {
    case REQUEST_POST_BODY:
      // here I need to set post.isFetching => true
    case RECEIVE_POST_BODY:
      // here I need to set post.isFetching => false and post.body => action.body
    default:
      return state;
    }
  }

  function requestPostBody(id) {
    return {
      type: REQUEST_POST_BODY,
      id
    };
  }

  function receivePostBody(id, body_from_server) {
    return {
      type: RECEIVE_POST_BODY,
      id,
      body: body_from_server
    };
  }

  dispatch(requestPostBody(3));
  dispatch(receivePostBody(3, {id:3, body: 'blablabla'}));

推荐答案

With Arrays

如果您更喜欢使用数组,那么您可以编写一个只处理单个 post 对象的 reducer.

With Arrays

If you'd prefer to stick with arrays, then you can write a reducer that just tackles single post objects.

export default function reducePost(post, action) {
  if(post.id !== action.id) return post;

  switch(action.type) {
  case REQUEST_POST_BODY:
    return Object.assign({}, post, { isFetching: true });
  case RECEIVE_POST_BODY:
    return Object.assign({}, post, { isFetching: false, body: action.body });
  default:
    return post;
}

你的 root reducer 会变成:

Your root reducer would become:

export default function posts(state = initialState, action) {
  return state.map(post => reducePost(post, action);
}

我们只是在列表中的每个帖子上运行我们的新减速器,以返回更新的帖子数组.在这种情况下,唯一 id 将确保仅更改一项.

We're just running our new reducer over each post in the list, to return an updated array of posts. In this case, the unique id will ensure that only one item will be changed.

如果每个项目都有唯一的字符串/数字 ID,那么您可以翻转数组并使用 object 代替.

If each item has a unique string/number id, then you can flip your array around and use an object instead.

const initialState = {
  items: {
    3: {id:3, title: '1984', isFetching:false},
    6: {id:6, title: 'Mouse', isFetching:false}
  };
}

然后你可以简化你的减速器.

Then you can simplify your reducer.

switch (action.type) {
case REQUEST_POST_BODY:
  let id = action.id;
  return Object.assign({}, state, {
    [id]: Object.assign({}, state[id], { isFetching: true })
  });
case RECEIVE_POST_BODY:
  let id = action.id;
  return Object.assign({}, state, {
    [id]: Object.assign({}, state[id], {
      isFetching: false,
      body: action.body
    })
  });
default:
  return state;
}

如果您也乐于尝试一些 ES7 语法,您可以使用 Babel 启用对象扩展运算符并重写对 Object.assign 的调用.

If you're happy to experiment with some ES7 syntax too, you can enable the Object spread operator with Babel and rewrite the calls to Object.assign.

switch (action.type) {
case REQUEST_POST_BODY:
  let id = action.id;
  return {
    ...state,
    [id]: {...state[id], isFetching: true }
  };
case RECEIVE_POST_BODY:
  let id = action.id;
  return {
    ...state,
    [id]: {
      ...state[id],
      isFetching: false,
      body: action.body
    }
  };
default:
  return state;
}

如果您不太热衷于使用扩展语法,那么仍然可以使 Object.assign 更可口.

If you're not so keen on using the spread syntax, then it's still possible to make Object.assign a bit more palatable.

function $set(...objects) {
  return Object.assign({}, ...objects); 
}
case RECEIVE_POST_BODY:
  let id = action.id;
  return $set(state, {
    [id]: $set(state[id], {
      isFetching: false,
      body: action.body
    })
  });

这篇关于在 redux reducer 中更新状态的正确方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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