反应& Redux - "动作必须是普通对象"

时间:2016-12-23 13:31:41

标签: reactjs typescript redux

我试图弄清楚为什么这不起作用。

我在打字稿上使用React和Redux。

我有以下代码:

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {Action} from 'redux';

/** Redux Action **/
class AddTodo implements Action {
   type: string;
   id: number;
   text: string;
   constructor(id: number, text: string) {
       this.type = 'ADD_TODO';
       this.id = id;
       this.text = text;
   }
}

// ...

class TodoApp extends React.Component {
   public render(): JSX.Element {
      return (
          <div>
              <button onClick={() => {
                 store.dispatch(new AddTodo(0, 'Test'));
              }}>
                 Add Todo
              </button>
          </div>
      );
   }
}

// ...

当我点击按钮时,我在控制台上收到以下错误:

  

未捕获错误:操作必须是普通对象。使用自定义中间件进行异步操作。

我不明白Redux为什么认为这是异步动作或复杂对象。

我的减速器甚至没有被执行。它们看起来像这样:

const todoReducer: Reducer<Todo> = (state: Todo, action: Action): Todo => {
   if (action instanceof AddTodo)
      return { id: action.id, text: action.text, completed: false } as Todo;
   // ...
   else
      return state;
};

const todosReducer: Reducer<Todo[]> = (state: Todo[] = [], action: Action): Todo[] => {
   if (action instanceof AddTodo)
       return [...state, todoReducer(undefined, action)];
   // ...
   else
       return state;
}

如果我传入{ type: 'ADD_TODO', id: 0, text: 'Test' }而不是new Action(0, 'Test'),则错误消失,但由于减速器上的条件,我的操作未正确执行。

你知道这里发生了什么吗?

1 个答案:

答案 0 :(得分:1)

丹·阿布拉莫夫本人解释道:

https://github.com/reactjs/redux/issues/992

基本上,如果使用我的方法,操作(记录/重放功能)的序列化和反序列化将不起作用,因为类型信息不会持久存在。

引用丹:

  

换句话说,这是一种反模式:

function reducer(state, action) {
   if (action instanceof SomeAction) {
     return ...
   } else {
     return ...
   }
}
  

如果我们让TypeScript用户成为可能,我知道JavaScript用户会受到诱惑并会滥用它,因为许多来自传统OO语言的人习惯用这种方式编写代码。然后他们将失去Redux中记录/重播的好处。

     

Redux的一个要点是强制执行一些我们认为重要的限制,如果没有强制执行,则不允许以后使用丰富的工具。如果我们让人们使用类来执行操作,他们就会这样做,并且实现像redux-recorder这样的东西是不可能的,因为不能保证人们使用普通的对象操作。特别是如果样板项目突然决定采用类,因为“哇,现在允许它,它一定是个好主意”。