Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.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 - Fatal编程技术网

Javascript 如何使用依赖状态组合redux还原器

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

我正在开发一个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_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()
    ,它可以将小部件列表作为一个附加参数提供给我的
    currentlySelectedWidgets()
    reducer:我认为这可能是我最好的选择

我很想听到关于其他人如何管理类似情况的任何其他建议,似乎管理“当前选择”必须是其他人必须解决的常见状态问题。

如果您使用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
现在提供对min
x
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)
不太可能有人照样复制此代码,只是以防万一。