Why do you need “actions” as data in abbreviation?

The Redux documentation says that I have to do actions and action creators, for example:

function addTodo(filter) { return { type: SET_VISIBILITY_FILTER, filter } } 

Then write gearboxes, for example:

 function todoApp(state = initialState, action) { switch (action.type) { case SET_VISIBILITY_FILTER: return Object.assign({}, state, { visibilityFilter: action.filter }); } } 

Then I invoke the action using submit:

 store.dispatch(addTodo("Ask question on stackoverflow")); 

There seems to be one, one correspondence between actions and gears; the sole purpose of this action is to select a gearbox and provide input for this gearbox.

Why don't we skip the average person and define actions with gearboxes and action creators with functions that produce gearboxes? Then dispatch will take one argument, a reducer / action of type State => State :

 // Action/reducer. (Parametrised state transformer, really.) const addTodo = text => state => { return Object.assign({}, state, { visibilityFilter: action.filter }); } // Dispatch takes as a argument the action/reducer store.dispatch(addTodo("Ask question on stackoverflow")); 

You will lose the ability to serialize actions, but otherwise, it seems that you will get rid of the creators of template actions and more clearly express the connection between actions and reducers. If you are in Typescript, you also get the option of checking data types in actions that are difficult to express otherwise .

So, what are the reasons for acting as data for me?

+7
javascript redux typescript
source share
3 answers

The main goal of action in Redux is to reduce state. The Reduce method will be called over an array of actions (that's why he called the reducer ) Example:

 import reducer from './reducer'; const actions = [ {type: 'INIT'}, {type: 'SOME_ACTION', params: {...}}, {type: 'RECEIVE_DATA', data: [...]}, {type: 'SOME_ANOTHER_ACTION', params: {...}}, {type: 'RECEIVE_DATA', data: [...]}, ... ]; const finalState = actions.reduce(reducer, undefined); 

Creators of an Action is a function that can create actions . It is not necessary for the action creator to create only one action.

In fact, if your reducer can receive functions instead of objects, your actions will be functions, and this will be the main goal, but you may lose some of the benefits of Redux functionality.

In this case, the gearbox will be implemented as follows:

 function reducer(state, action) { return action(state); } 

Reasons why you can create actions in the {type: 'ACTION_NAME'} format:

  • Redux DevTools expects this format.
  • You need to keep the sequence of actions.
  • The gearbox performs state conversions for the worker.
  • Everyone in the Redux ecosystem uses this format. This is a kind of agreement.
  • Hot restart options (your saved functions will not restart).
  • You need to send actions as on the server.
  • Debugging Benefits - View a stack of actions with action names.
  • Writing unit tests for the gearbox: assert.equal(finalState, expectedState) .
  • A more declarative code — the name and parameters of the action — is “what to do” rather than “how to do” (but addTodo('Ask question') also declarative).

Note on the relationship between action creators and state changes

Just compare the two entries:

At first:

 function someActionCreator() { return { type: "ADD_TODO", text: "Ask question on stackoverflow" }; // returns object } 

Secondly:

 function someActionCreator() { return addTodo("Ask question on stackoverflow"); // returns function } 

“In both cases, we see that the code is declarative and the creator of the action is separate from the state change. You can reuse addTodo or send two addTodo or use middleware or send compose(addTodo('One'), addTodo('Two')) . The main difference is that we created an object and a function and placed it in the code in which the state changes.

+4
source share

Good question.

Separating actions from state changes is really a thread pattern, not a specific Redux thing. (Although I will answer a question with a link to Redux.) This is an example of a loose connection.

In a simple application, the tight connection between actions and state changes can be wonderful. But in a larger application, this can be a headache. For example, your addTodo action may cause changes in several parts of the state. Separation of actions from state changes - the latter is carried out in gearboxes - allows you to write smaller functions that are easier to reason and more subject to testing.

In addition, decoupling your actions and state changes allows your gear logic to be more reusable. for example, Action X can initiate changes in state A and B, while action Y only causes a change in state A.

In addition, this denouement leads to the appearance of a Redux function called middleware. Middleware listens for activity submission. It does not change the state of the application, but it can read the current state and the next state, as well as information about the action. An intermediate tier is useful for functionality other than core application logic, for example. logging and tracking (dev tools were mentioned in the previous answer).

[UPDATE] But why actions as objects?

If it were just a matter of functions invoking other functions, then the decoupling would be much less explicit. Indeed, he might even get lost; since most actions allow only one state change, developers can get tired of one function that calls one function and completely get rid of separation.

Another thing is the model of the data stream flow . One-way data flow is very important for the Flux / React paradigm. A typical Redux / React looks something like this: Store state -> Higher order React components -> Lower order React components -> DOM . Action is an aberration in a model; This is the back arrow that transfers data from the view to the store. It makes sense to make the action as loud and decisive as possible. Not just a function call, but a sent object. As if your application was announcing hey! Something important happened here!

+3
source share

There is no mutual comparison between actions and reducers. Per Dan Abramov comments on https://github.com/Pitzcarraldo/reduxible/issues/8 :

This reinforces a very common misconception regarding Redux: namely, that action creators and reducers are one-to-one.

This is true only in trivial examples, but in real applications it is extremely limited. Beginners are exposed to this scheme of a pair of gearboxes and action creators, and do not understand that they are intended for many, many and are untied.

Many gearboxes can handle one action. One gearbox can handle many actions. Combining them together negates the many benefits of how Flux and Redux applications scale. This leads to bloat code and unnecessary communication. You lose the flexibility to respond to the same action from different places, and your action creators begin to act as "setters" associated with a particular form of state, thereby also linking components to it.

Regarding the actions and the type parameter, the other answers are correct. This is intentional, as Redux was designed, and it was intended to benefit serialization for debugging purposes.

+2
source share

All Articles