Redux:如何根据其他状态创建状态?
Posted
技术标签:
【中文标题】Redux:如何根据其他状态创建状态?【英文标题】:Redux: How to create state based on other state? 【发布时间】:2018-08-23 15:00:41 【问题描述】:我正在尝试学习 Redux,所以:我正在学习 Action creators、actions、reducers、dispatchers...
现在,我正在尝试学习如何根据其他状态生成 x 状态。对于案子,姓名和爱好。
我有类型,常量:NAMES
和 HOBBIES
,它们被我的动作创建者使用,它们将它们作为类型和有效负载返回,例如: type: HOBBIES, request: payload
然后我有我的 reducer 文件,我在其中通过两种情况(和默认情况)的操作进行切换
我从我的主文件 App.js 进行调度,并以道具的形式访问这些状态。
function mapStateToProps(state)
return
names: state.names,
hobbies: state.hobbies
function mapDispatchToProps(dispatch)
return bindActionCreators( grabNames, grabHobbies , dispatch);
export default connect(mapStateToProps,mapDispatchToProps)(myApp);
我正在使用 combineReducers (index.js)
const rootReducer = combineReducers(
names: namereducer,
hobbies: hobbyreducer
);
目前我有以下redux状态。
names: [
name: "A", id: "1",
name: "B", id: "2",
name: "C", id: "3"
]
和
hobbies: [
basedId: "1", hobby: "cooking",
basedId: "2" hobby: "reading",
basedId: "3" hobby: "gaming",
basedId: "1" hobby: "reading"
]
结果应该是包含每个basedId
的爱好的对象数组,当然遵循 Redux 的良好实践。
result: [
name: "A", id: "1", hobby: ["cooking", "reading"],
name: "B", id: "2", hobby: "reading",
name: "C", id: "3", hobby: "gaming"
]
问题是我从未超越简单的地图和 [...state, action.data];
我试图找到解决方案,但我找不到。我非常感谢任何帮助,因为我是新手。
【问题讨论】:
只要“爱好”只包含一个字符串,考虑通过简单地将它们保存在名称缩减器内的数组中来维持这种 1:N 关系(一个人有很多爱好)。只有当“爱好”成为具有其他属性的更复杂对象时(显然,您不想在state.names
中复制),您才需要使用像reselect
这样的库来建立此映射。顺便说一句,mapStateToProps 也可以正常工作,这只是一种优化。
【参考方案1】:
我认为不要从您已存储的数据中生成新状态,因为您将存储相同(但已修改)的数据两次。而是在需要时执行此数据操作并构造您的 result
对象。
话虽如此,下面是你的答案,带有一点 ES6 香料:
names.map(name => (
...name, hobby: hobbies.filter(hobby => hobby.basedId === name.id).map(hobby => hobby.hobby)
))
【讨论】:
【参考方案2】:redux 原则之一是“单一事实来源”。 这意味着不要重复数据,它更高效,并且可以防止许多错误和问题。
但如果你只是想在两个 reducer 之间共享数据,你可以这样做 通过使用redux thunk middleware
基本上,您可以在使用 dispatch 启动操作之前从其他 reducer 状态读取数据。
简单的操作:
function myAction()
return
type: DO_SOMTHING
;
thunk 操作
function myAction()
return (dispatch, getState) =>
// get state contains all existing reducers states
const reducerTwo = getState();
dispatch(
type: DO_SOMTHING,
data: reducerTwo.prop
);
;
【讨论】:
【参考方案3】:这是reselect 的完美用例。您的代码基本上如下所示:
import createSelector from 'reselect';
const namesSelector = state => state.names;
const hobbiesSelector = state => state.hobbies;
const combineNamesAndHobbies = (names, hobbies) =>
names.map(name => (
...name,
hobby: hobbies.filter(hobby => hobby.basedId === name.id)
.map(hobby => hobby.hobby)
));
const resultSelector = createSelector(
[namesSelector, hobbiesSelector],
combineNamesAndHobbies
);
function mapStateToProps(state)
return
names: namesSelector(state),
hobbies: hobbiesSelector(state),
result: resultSelector(state)
这将导致您的myApp
组件具有这些props
:
names: [
name: "A", id: "1" ,
name: "B", id: "2" ,
name: "C", id: "3"
],
hobbies: [
basedId: "1", hobby: "cooking" ,
basedId: "2", hobby: "reading" ,
basedId: "3", hobby: "gaming" ,
basedId: "1", hobby: "reading"
],
result: [
name: "A", id: "1", hobby: ["cooking", "reading"] ,
name: "B", id: "2", hobby: ["reading"] ,
name: "C", id: "3", hobby: ["gaming"]
]
请注意,hobby
将始终是一个数组,我认为这是最佳实践。 (但您应该将其命名为 hobbies
。)
【讨论】:
【参考方案4】:我同意@xehpuk。通过使用reselect,如果相关状态都没有改变,您可以避免重新计算生成的状态,如果选择器函数被多次调用,例如在渲染循环中,则很有用,因此您不需要手动优化这部分。
为了减少所需的代码,您还可以尝试redux-named-reducers 并改写如下选择器:
const resultSelector = createSelector(
[namesModule.names, hobbiesModule.hobbies],
combineNamesAndHobbies
);
这增加了一些开销计算以换取快捷方式
【讨论】:
以上是关于Redux:如何根据其他状态创建状态?的主要内容,如果未能解决你的问题,请参考以下文章