An action object can have other fields with additional information about what happened. By convention, we put that information in a field called payload
const addTodoAction = {
type: 'todos/todoAdded',
payload: 'Buy milk'
}
An action creator is a function that creates and returns an action object
const addTodo = text => {
return {
type: 'todos/todoAdded',
payload: text
}
}
A reducer is a function that receives the current state and an action object, decides how to update the state if necessary, and returns the new state: (state, action) => newState.
const initialState = { value: 0 }
function counterReducer(state = initialState, action) {
// Check to see if the reducer cares about this action
if (action.type === 'counter/increment') {
// If so, make a copy of `state`
return {
...state,
// and update the copy with the new value
value: state.value + 1
}
}
// otherwise return the existing state unchanged
return state
}
- They should only calculate the new state value based on the state and action arguments
- They are not allowed to modify the existing state. Instead, they must make immutable updates, by copying the existing state and making changes to the copied values.
- They must not do any asynchronous logic, calculate random values, or cause other "side effects"
The current Redux application state lives in an object called the store .
The store is created by passing in a reducer, and has a method called getState that returns the current state value
import { configureStore } from '@reduxjs/toolkit'
const store = configureStore({ reducer: counterReducer })
console.log(store.getState())
// {value: 0}
The Redux store has a method called dispatch
. The only way to update the state is to call store.dispatch()
and pass in an action object. The store will run its reducer function and save the new state value inside, and we can call getState()
to retrieve the updated value
store.dispatch({ type: 'counter/increment' })
console.log(store.getState())
// {value: 1}
You can think of dispatching actions as "triggering an event" in the application. Something happened, and we want the store to know about it. Reducers act like event listeners, and when they hear an action they are interested in, they update the state in response.
const increment = () => {
return {
type: 'counter/increment'
}
}
store.dispatch(increment())
console.log(store.getState())
// {value: 2}
Selectors are functions that know how to extract specific pieces of information from a store state value. As an application grows bigger, this can help avoid repeating logic as different parts of the app need to read the same data:
const selectCounterValue = state => state.value
const currentValue = selectCounterValue(store.getState())
console.log(currentValue)
// 2