3

I'm trying to figure out why is this not working.

I'm using React with Redux on Typescript.

I have the following code:

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>
      );
   }
}

// ...

When I click on the button, I'm getting the following error on console:

Uncaught Error: Actions must be plain objects. Use custom middleware for async actions.

I don't understand why is Redux assuming this is an async action or a complex object.

My reducers are not even being executed. They look like this:

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;
}

If I pass in { type: 'ADD_TODO', id: 0, text: 'Test' } instead of new Action(0, 'Test'), then the error is gone, but my action is not correctly executed because of the conditions on the reducer.

Do you know what is going on here?

9
  • could you please provide the snippet of your AddToDo? Commented Dec 23, 2016 at 14:13
  • You have created an "object constructor", not a plain object as the error message states. stackoverflow.com/questions/5876332/… Commented Dec 23, 2016 at 14:19
  • @SteliosVoskos I have already provided it. It is the class at the top of the above code. If you mean the add logic, it is on the reducers I posted on the bottom of the post. Commented Dec 23, 2016 at 14:19
  • 1
    @ctrlplusb I'm using TypeScript, not babel. And the generated JS code from TS does not contain any _classCallCheck method. Commented Dec 23, 2016 at 14:21
  • 1
    @ctrlplusb I have a return state as a default case. In any way, if the action is not recognized, it shouldn't throw this kind of error. Commented Dec 23, 2016 at 14:23

1 Answer 1

3

This is explained by Dan Abramov himself:

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

Basically, serialization and deserialization of actions (record / replay functionality) will not work if using my approach, because type information is not persisted.

Quoting Dan:

In other words, this is an anti-pattern:

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

If we make it possible for TypeScript users, I know JavaScript users will be tempted and will abuse this because many people coming from traditional OO languages are used to writing code this way. Then they will lose benefits of record/replay in Redux.

One of the points of Redux is to enforce some restrictions that we find important, and that, if not enforced, don't allow for rich tooling later on. If we let people use classes for actions, they will do so, and implementing something like redux-recorder will be impossible because there's no guarantee people use plain object actions. Especially if boilerplate projects suddenly decide to adopt classes because “wow, it’s allowed now, it must be a great idea”.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.