对于给定的reducer,我的redux状态树通常看起来像这样:
{
someField: 'some value',
// ... more fields
metadata: {
pending: false,
fetched: true,
}
}
通常,当我执行异步请求时,我会触发SOME_ACTION_REQUEST
操作,该操作会将metadata.pending
属性设置为true。当匹配的SOME_ACTION_RESPONSE
或SOME_ACTION_ERROR
事件稍后发生时,它会再次重置为false。
但是,我更新状态的方式有点冗长:
case actions.SOME_ACTION_REQUEST: {
return {
...state,
metadata: { ...state.metadata, pending: true },
};
}
有更简单的方法吗?
Object.assign({}, state, { metadata: { pending: true } })
也不是非常易读。
答案 0 :(得分:2)
这是进行不可变数据更新的典型示例。您可能需要仔细阅读Redux文档的新Structuring Reducers部分,以获取更多信息,尤其是Prerequisite Concepts和Immutable Update Patterns页。
答案 1 :(得分:1)
您可以使用reducer的嵌套结构。
其中有一个函数/ reducer命名元数据,调用它来更改字段。
示例代码
const metadata = (state = [], action = {}) => {
switch (action.type) {
case actions.SOME_ACTION_REQUEST::
return {...state, ...action.payload.metadata};
default:
return state;
}
};
const someReducer = (state = initalState, action = {}) => {
let metadata = {};
switch (action.type) {
case actions.SOME_ACTION_REQUEST: {
metadata = metadata(state.metadata, action)
return {
...state,
...metadata
};
}
}
};
答案 2 :(得分:0)
是的,它实际上是Redux的缺点,不仅如此 - 如果您使用MobX,您也会遇到同样的问题。所以,答案只是以某种方式概括它 - 编写一个reducers工厂,它将常量作为参数,并将它们合并一次,并将其重用于所有异步操作。
I've created a library对于这个问题,请随时查看。另外,请记住,原始Redux无论如何都非常冗长,并尝试以最佳方式掌握您的域模型。 您的示例将如下所示:
import { createTile } from 'redux-tiles';
const someTile = createTile({
type: ['some', 'example'],
fn: ({ api, params }) => api.get('/some/request', params),
});
dispatch(actions.some.example(params));
selectors.some.example(state)); // { isPending: true, error: null, data: null }
来自最后一个选择器的数据将在获得响应后自动更新 - 因此无需手动编写此类内容。
另一个问题是嵌套更新,你必须做同样的事情,但是我总是试图解决更多的冗长问题。但是,当然,它是一个非常简单的库,只尝试覆盖简单的用例 - 对于复杂的用例,我绝对建议你尝试定制的东西。