Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 在redux还原器中更新状态的正确方法_Javascript_Reactjs_Redux_Flux - Fatal编程技术网

Javascript 在redux还原器中更新状态的正确方法

Javascript 在redux还原器中更新状态的正确方法,javascript,reactjs,redux,flux,Javascript,Reactjs,Redux,Flux,我是redux和es6语法的新手。我用官方的redux教程制作我的应用程序,还有这个 下面有一个JS代码段。我的观点是——在posts中定义REQUEST_POST_BODY和RECEIVE_POST_BODY案例。 主要困难-在存储中查找和更新正确的对象 我尝试使用示例中的代码: return Object.assign({}, state, { [action.subreddit]: posts(state[action.subreddit], action) }) 但它使

我是redux和es6语法的新手。我用官方的redux教程制作我的应用程序,还有这个

下面有一个JS代码段。我的观点是——在posts中定义REQUEST_POST_BODY和RECEIVE_POST_BODY案例。 主要困难-在存储中查找和更新正确的对象

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

  return Object.assign({}, state, {
    [action.subreddit]: posts(state[action.subreddit], action)
  })
但它使用了简单的帖子数组。不需要通过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'}));
使用数组 如果您更喜欢使用数组,那么您可以编写一个reducer,它只处理单个
post
对象

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;
}
您的根减速器将成为:

export default function posts(state = initialState, action) {
  return state.map(post => reducePost(post, action);
}
我们只是在列表中的每个帖子上运行新的reducer,以返回更新后的帖子数组。在这种情况下,唯一id将确保仅更改一项

有物体 如果每个项目都有一个唯一的字符串/数字id,则可以翻转数组并使用
对象

const initialState = {
  items: {
    3: {id:3, title: '1984', isFetching:false},
    6: {id:6, title: 'Mouse', isFetching:false}
  };
}
然后你可以简化你的减速器

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
的调用

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
更容易接受

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
    })
  });

如果我理解正确的话,你很难得到你想要的具体职位

首先,让reducer同时更新数组和其中的对象会使读取和维护变得困难。我建议你看这篇关于数组的减速器组成的解释。 您可以使用这里描述的技术来简化代码

在您的例子中,您将使用
posts
reducer和
post
reducer,而
posts
reducer调用
post
reducer

至于找到合适的工作对象,丹·普林斯的建议使之更容易。 使用对象映射而不是数组将使您更容易。Dan回答中的相关代码片段:

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

我几乎通过使用
Object.assign
实现了对象缩减器,这很有效,但是随着我们的项目的发展,我们添加了大量的依赖组件,它变得非常低效,渲染速度也非常慢

如果我知道的话,我会从一开始就使用它

基本上,您使用immer如下所示,其中示例有一个如下所示的
layers
对象:

const initialState = {
  layers: {
   'layer1': { selected: false },
   'layer2': { selected: true }
  }
}
Reducers.js(摘录)

Actions.js(摘录)

参考资料:


如果
id
s总是唯一的,那么最好将
items
设置为对象而不是数组。然后,您可以使用
items[id]
通过id查找。简单而漂亮!谢谢所以,有一个稍微不同的存储数据结构,我必须改变我的组件渲染方法。Code{this.props.data.map((item,id)=>引发错误:TypeError:this.props.data.map不是render的函数在这里迭代新对象(而不是数组)的正确方法是什么?它应该是这样的:for(让[id,item]的object.entries(this.props.data)){有效,或者您也可以对键进行迭代。
Object.keys(this.props.data).map(k=>
。如果您使用Lodash或下划线,则像
map
filter
这样的函数会迭代对象自身的属性以及数组,在这种情况下非常有用。应该有一个逗号(“,”)在案例请求后正文中的“…状态”之后。
import produce from 'immer'
import has from 'lodash/has'
export const layers = (state = null, action) => {
  switch (action.type) {
    case ADD_LAYER:
      // Using `immer.produce` only for consistency 
      // clearly the whole object changes in this case.
      return produce(state, layers => {
        // Take a copy of the prebuilt layer
        var layer = Object.assign({}, action.layer)
        // Add some defaults
        if (!has(layer, 'selected')) {
          layer.selected = false
        }
        layers[action.id] = layer
      })
    case SELECT_LAYER:
      return produce(state, layers => {
        layers[action.id].selected = true
      })
    case UNSELECT_LAYER:
      return produce(state, layers => {
        layers[action.id].selected = false
      })
    default:
      return state
  }
}
export const addLayer = id => ({
  type: ADD_LAYER,
  id
})

export const selectLayer = id => ({
  type: SELECT_LAYER,
  id
})

export const unSelectLayer = id => ({
  type: UNSELECT_LAYER,
  id
})