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


← Back to notes