createAction & createReducer

Redux Toolkit provides a direct way to define an action creator, eg.:

const increment = createAction('counter/increment');

which is equivalent to:

function increment(amount) { return { type: 'counter/increment', payload: amount, } }

createAction() accepts an optional second argument: a "prepare callback" that will be used to construct the payload value., eg.:

import { createAction, nanoid } from '@reduxjs/toolkit' const addTodo = createAction('todos/add', function prepare(text) { return { payload: { text, id: nanoid(), createdAt: new Date().toISOString(), }, meta: { x: 10 }, error: false } }) console.log(addTodo('Write more docs')) /* { type: 'todos/add', payload: { text: 'Write more docs', id: 'ruddl8iwbhf', createdAt: '2019-10-03T07:53:36.581Z' }, meta: { x:10 }, error: false } */

An action creator returned from createAction() has the method match(), which can be called to test for equality:

const increment = createAction('INCREMENT') function someFunction(action) { // accessing action.payload might result in an error here if (increment.match(action)) { // action.payload can be used here } } const chosen_actions = (actions) => // actions is an array of actions actions .filter(increment.match) .map((action) => { // action.payload can be safely here }) );

You can use one of the two createReducer() notations to easily define a reducer:

1. 'Builder Callback' notation
2. 'Map Object' notation
Under the hood, createReducer() uses Immer, allowing you to mutate the state directly in your reducers.
In practice, a reducer should either return a new state or mutate the state in place, but not both.
Multiple matchers may handle a single action, in the order they were defined, after the case reducer ran.
Immer makes it hard to log the state in a reducer. As a workaround, you can use current(), a function re-exported from Immer to Redux Toolkit.