Javascript 如何使用依赖状态组合redux还原器
我正在开发一个React/Redux应用程序,它允许将“小部件”添加到页面并在2D空间中进行操作。需要同时选择和操作多个小部件。我当前状态树的简化版本如下所示Javascript 如何使用依赖状态组合redux还原器,javascript,reactjs,redux,Javascript,Reactjs,Redux,我正在开发一个React/Redux应用程序,它允许将“小部件”添加到页面并在2D空间中进行操作。需要同时选择和操作多个小部件。我当前状态树的简化版本如下所示 { widgets: { widget_1: { x: 100, y: 200 }, widget_2: { x: 300, y: 400 }, widget_3: { x: 500, y: 600 } }, selection: { widgets: [ "widget_1", "widget
{
widgets: {
widget_1: { x: 100, y: 200 },
widget_2: { x: 300, y: 400 },
widget_3: { x: 500, y: 600 }
},
selection: {
widgets: [ "widget_1", "widget_3" ]
}
}
我目前有两个还原器来管理这个树,一个管理小部件
状态,另一个管理选择
状态。选择状态缩减器可以简化为(注意:我也在使用Immutable.js)
这一切似乎都很好,但我现在有一个要求,我正在努力适应这个模式
出于用户界面的目的,我需要让当前选择具有一个x/y属性,该属性反映当前选择的小部件x/y坐标的左上角。一个示例状态可能看起来像
{
widgets: {
widget_1: { x: 100, y: 200 },
widget_2: { x: 300, y: 400 },
widget_3: { x: 500, y: 600 }
},
selection: {
x: 100,
y: 200,
widgets: [ "widget_1", "widget_3" ]
}
}
这里的逻辑相当简单,例如,查找所有选定小部件x
和y
值的min()
,但我不确定如何处理减速机的组成,因为currentlySelectedWidgets
减速机无法访问状态树的小部件
部分。我考虑过
- 将减速器合并为一个减速器:这似乎不是一个很好的可扩展解决方案
- 用动作传递当前的小部件列表:这看起来特别讨厌
- 找到一种更好的建模状态树的方法:我有一个想法,但任何替代版本似乎都有其他缺点
- 构建一个自定义的
,它可以将小部件列表作为一个附加参数提供给我的combineReducers()
reducer:我认为这可能是我最好的选择currentlySelectedWidgets()
我很想听到关于其他人如何管理类似情况的任何其他建议,似乎管理“当前选择”必须是其他人必须解决的常见状态问题。如果您使用thunk中间件(),您可以使
设置选择
操作成为thunk,这将允许它读取整个状态,然后再发送将由您的减速机接收的调度
// action creator
function setSelection(selectedWidgetId) {
return (dispatch, getState) => {
const {widgets} = this.getState();
const coordinates = getSelectionCoordinates(widgets, selectedWidgetIds);
dispatch({
type: SET_SELECTION,
payload: {
widgets: selectedWidgets,
x: coordinates.x,
y: coordinates.y
}
});
}
这样,您就可以在选择缩减器中获得所需的所有信息,而无需将所有小部件对象的列表传递给您的操作。这是一个很好的用例: 创建选择器以访问您的状态并返回派生数据 例如:
import { createSelector } from 'reselect'
const widgetsSelector = state => state.widgets;
const selectedWidgetsSelector = state => state.selection.widgets;
function minCoordinateSelector(widgets, selected) {
const x_list = selected.map((widget) => {
return widgets[widget].x;
});
const y_list = selected.map((widget) => {
return widgets[widget].y;
});
return {
x: Math.min(...x_list),
y: Math.min(...y_list)
};
}
const coordinateSelector = createSelector(
widgetsSelector,
selectedWidgetsSelector,
(widgets, selected) => {
return minCoordinateSelector(widgets, selected);
}
);
coordinateSelector
现在提供对minx
和y
属性的访问。只有当widgetselector
或selectedwidgetselector
状态发生更改时,上述选择器才会更新,这使得这是一种非常有效的方式来访问您要访问的属性,并避免状态树中的重复。我使用的是:
CommonReducer.js
export default function commonReducer(state = initialState.doesNotMatter, payload) {
switch (payload.type) {
case "JOINED_TYPE": {
let newState = Object.assign({}, state);
return newState;
}
default:
return state;
}
}
import commonReducer from './commonReducer';
export default function someReducer(state = initialState.somePart, payload) {
switch (payload.type) {
case "CUSTOM_TYPE": {
let newState = Object.assign({}, state);
return newState;
}
default:{
return commonReducer(state, payload);
}
}
}
SomeOtherReducer.js
export default function commonReducer(state = initialState.doesNotMatter, payload) {
switch (payload.type) {
case "JOINED_TYPE": {
let newState = Object.assign({}, state);
return newState;
}
default:
return state;
}
}
import commonReducer from './commonReducer';
export default function someReducer(state = initialState.somePart, payload) {
switch (payload.type) {
case "CUSTOM_TYPE": {
let newState = Object.assign({}, state);
return newState;
}
default:{
return commonReducer(state, payload);
}
}
}
您可以尝试使用:
它允许您在代码中的任何位置获取状态,如下所示:
const localState1 = getState(reducerA.state1)
const localState2 = getState(reducerB.state2)
或将外部依赖状态指定给减速器,如下所示:
reducerA.extState1=reducerB.state1
然后像这样访问它:
getState(reduerA.extState1)谢谢你的帮助,它似乎可以解决这个问题,我很想看看这种方法随着代码库的增长可以扩展到什么程度,但我们会看到的。我今天无法回答更多问题,所以我这样问。如果@Ashley想从
currentlySelectedWidgets(状态、操作)
reducer中删除一个特定的小部件,该怎么办?如何做到这一点?在尝试实施了Hummlas基于thunk的方法和基于重选的方法之后,我觉得这种方法更适合我的模型,并提供了一个更干净、更易于维护的解决方案。我想我正在慢慢学习的一般经验法则是,不要在状态树中存储任何可以从现有树重新计算的内容。忘记提及,在这个示例答案中有一个小错误,最后的minSelector(widgets,selected)
应该是minCoordinateSelector(widgets,selected)
不太可能有人照样复制此代码,只是以防万一。