在创建新的widget-Reactjs,Redux时,在调度之间检测到状态突变

时间:2018-05-24 13:28:41

标签: reactjs redux

创建小部件列表时出错

如果我第一次点击小部件列表我能够创建小部件(小部件1)。

如果我创建另一个小部件,我会收到错误(状态突变)。

如果我创建另一个小部件,我可以创建没有错误的小部件(小部件3)

错误:在路径``中的调度之间检测到状态突变。这可能会导致不正确的行为。

addWidget = (widgetType) => {
let newWidget = {};
switch (widgetType) {
  case 'venn':
    newWidget = {
      widgetName: `widget ${this.state.widgetCount}`,
      widgetType: 'venn',
      leftTarget: '',
      rightTarget: '',
      leftTargetValue: 0,
      rightTargetValue: 0,
      position: { row: 0, col: 0 },
    };
    break;
default:
    newWidget = {
      widgetName: `Default ${this.state.widgetCount}`,
      widgetType: 'venn',
      leftTarget: '',
      rightTarget: '',
    };
    break;
}
this.setState(prevState => ({
  widgetsList: [...this.state.widgetsList, newWidget],
  isHidden: !prevState.isHidden,
  widgetCount: this.state.widgetCount + 1,
}), () => this.props.storyboardActions.addWidget(newWidget, this.props.selectedBoard.boardId));  
};

减速

case types.ADD_NEW_WIDGET: {
  const newBoardList = state.boardList.map((item) => {
    if (item.boardId === action.selectedBoardId) {
      return {
        ...item,
        modifiedAt: Date.now(),
        widgetList: [...(item.widgetList || []), { widgetId: uuid(), ...action.newWidget }],
      };
    }
    return item;
  });
  return { ...state, boardList: [...newBoardList] };
}

动作

export const addWidget = (newWidget, selectedBoardId) => ({
type: types.ADD_NEW_WIDGET,
payload: { 
widget: newWidget,
boardId: selectedBoardId,
},
});

2 个答案:

答案 0 :(得分:1)

编辑:动作创建者中的错误

尝试使用action.payload传递所有数据。你现在有了你的属性名称的错误,并且你正在以错误的顺序调用params的动作创建者:

// Action Creator
export const addWidget = (newWidget, selectedBoardId) => ({  // <-- Param order
  type: types.ADD_NEW_WIDGET,
  payload: {  // <-- Use payload object
    boardId: selectedBoardId,  // <-- These key names
    widget: newWidget,
  }
});


// Reducer
case types.ADD_NEW_WIDGET: {
  const { boardId, widget } = action.payload;  // <-- Get the data out
  const newBoardList = state.boardList.map(item => {
    if (item.boardId === boardId) {
      const currentWidgetList = item.widgetList || [];
      const newWidgetList = [
        ...currentWidgetList,
        {
          widgetId: uuid(),
          ...widget
        }
      ];

      return {
        ...item,
        modifiedAt: Date.now(),
        widgetList: newWidgetList
      };
    }

    return item;
  });
  return { ...state, boardList: newBoardList };
}

我可以看到您的storyboardActions.addWidget actionCreator吗?

我知道可能出现什么问题。 spread运算符是一个浅层克隆,因此不能保证不可变。 (查看cloneDeep选项。)

但是,我并不认为正在变异的是什么。我对您发布的代码最好的想法是widgetName,因为它依赖于this.state.widgetCount来获取唯一名称,但setState方法是异步的,所以从技术上来说它有机会出错(我想。)

我稍微重构了你的代码。我的变化不大,所以我不指望这个解决问题。但是像这样将这些位分开会让你有机会在console.logs中投入,以便有希望找到发生突变的地方。

让我知道这是否会有所不同:

getNewWidget = type => {
  switch (widgetType) {
    case "venn":
      return {
        widgetName: `widget ${this.state.widgetCount}`,
        widgetType: "venn",
        leftTarget: "",
        rightTarget: "",
        leftTargetValue: 0,
        rightTargetValue: 0,
        position: { row: 0, col: 0 }
      };
    default:
      return {
        widgetName: `Default ${this.state.widgetCount}`,
        widgetType: "venn",
        leftTarget: "",
        rightTarget: ""
      };
  }
};

addWidget = widgetType => {
  const newWidget = this.getNewWidget(widgetType);
  this.setState(
    {
      widgetsList: [...this.state.widgetsList, newWidget],
      isHidden: !this.state.isHidden,
      widgetCount: this.state.widgetCount + 1
    },
    () =>
      this.props.storyboardActions.addWidget(
        newWidget,
        this.props.selectedBoard.boardId
      )
  );
};

减速

case types.ADD_NEW_WIDGET: {
  const newBoardList = state.boardList.map(item => {
    if (item.boardId === action.selectedBoardId) {
      const currentWidgetList = item.widgetList || [];
      const newWidgetList = [
        ...currentWidgetList,
        {
          widgetId: uuid(),
          ...action.newWidget
        }
      ];

      return {
        ...item,
        modifiedAt: Date.now(),
        widgetList: newWidgetList
      };
    }

    return item;
  });
  return { ...state, boardList: newBoardList };
}

答案 1 :(得分:0)

一个导致我犯此错误的常见错误是,当我从道具克隆到状态时。

getFields(props) {
  return ((props.resources.fields && [...props.resources.fields]) || []).map(
    field => {
      field.checked = false;
      return field;
    }
  );
}

this.setState({ fields: getFields(props) });

在上面的示例中,fields是一个对象数组。而且我没有进行深层复制,而是使用[...props.resources.fields]进行了浅层复制。

进行深层复制可以解决此问题。因此,对于我来说,我做了如下的浅层复制:

getFields(props) {
  return ((props.resources.fields && [...props.resources.fields]) || []).map(
    item => {
      const field = { ...item };
      field.checked = false;
      return field;
    }
  );
}