Javascript 在redux还原器中更新状态的正确方法
我是redux和es6语法的新手。我用官方的redux教程制作我的应用程序,还有这个 下面有一个JS代码段。我的观点是——在posts中定义REQUEST_POST_BODY和RECEIVE_POST_BODY案例。 主要困难-在存储中查找和更新正确的对象 我尝试使用示例中的代码: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) }) 但它使
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
})