Redux Primer
Redux Primer
What do you start with?
Actions
What are Actions?
- User interactable actions
- Events in the application logic
What does an action look like?
Its a javascript object
{
"type": String,
"payload": JSONValue
}The type is a string constant typically representing an action name. The payload is the data associated with the action event
Eg
{
"type": "ADD_POST",
"payload": {
"tags": ["primer"],
"text": "What do you start with?..."
}
}Would it be convenient if we had helper functions to create the action objects?
Yes, they are called action creators
function addPost({tags, text}){
return {
type: "ADD_POST",
payload: {
tags,
text
}
}
}Can we do better?
Yes, createAction, thanks @reduxjs/toolkit
const { createAction } = require('@reduxjs/toolkit')
addPost = createAction('ADD_POST')
addPost({tags: ["primer"], text: "What do you start with?..."})
{
type: 'ADD_POST',
payload: {
tags: [ 'primer' ],
text: 'What do you start with?...'
}
}Whats the next step?
Reducers
What are reducers?
Reducers manage your state using prevstate and action to give you nextstate
PrevState + Action => NextState
What do they look like?
Here’s a trivial example of a reducer
let initialState = 0
function counterReducer(state = initialState, action){
switch(action.type){
case "INCREMENT":
return state + 1
case "DECREMENT":
return state - 1
default:
return state
}
}
counterReducer(10, {type: "INCREMENT"})11
Can we do better?
Yes, createReducer, thanks again @reduxjs/toolkit
const { createReducer } = require('@reduxjs/toolkit')
let increment = createAction('counter/increment')
let decrement = createAction('counter/decrement')
initialState = 0
counterReducer = createReducer(initialState, (builder) => {
builder
.addCase(increment, (state, action) => state + 1)
.addCase(decrement, (state, action) => state - 1)
})
counterReducer(10, increment())11
Can we couple counter actions & counter reducer for convenience?
Yes, its called a slice
Why is it called slice?
Because they are a slice of the global state
const { createSlice } = require('@reduxjs/toolkit')
initialState = 0
const counterSlice = createSlice({
name: 'counter',
initialState,
reducers: {
increment: (state) => state + 1,
decrement: (state) => state - 1
},
})
increment = counterSlice.actions.increment
counterReducer = counterSlice.reducer
counterReducer(10, counterSlice.actions.increment())
11
From this point on, reducers and slices may be used interchangeably
How to decide what reducers to make?
Every reducer in the store(global state) is associated with a key
Eg - The value returned by counterReducer will be associated with key count in global state.
{
"count": counterReducer
}So one good way to figure out the reducers is by determining the states you will access.
Whats the next part?
Store
Whats a store?
The store is the global state
How do you make a store?
const { configureStore } = require('@reduxjs/toolkit')
const store = configureStore({
reducer: {
count: counterSlice.reducer
}
})How do you change state?
By dispatching actions
store.dispatch(increment())
{ type: 'counter/increment', payload: undefined }How do you access the state?
store.getState()
{ count: 1 }Has redux come a long way?
Yes, thanks @reduxjs/toolkit