Skip to main content

Intro to Redux

Intro

Redux is a Javascript library that helps us manage state in more complicated applications. It is not designed to work exclusively with React, although it does integrate very well. It can be used on it’s own or with other JavaScript applications.

For the following samples to work you will of course have to install redux, so take care of that if you are following along.

Redux Cycle

Redux Cycle

Action

An object that contains information about how we want to change some data within our central state.

An action will contain a type and a payload.

Action Creator

A function that creates an action object. Each action will contain unique information, but the format of each action should be the same. So when we create the Action Creator we will be writing out a schema of the action.

Let us take an example where we are creating actions that update the state of several insurance policies and their claims.

const createPolicy = (name, amount) => {
return {
type: "CREATE_POLICY",
payload: {
name: name,
amount: amount,
},
}
}

const deletePolicy = name => {
return {
type: "DELETE_POLICY",
payload: {
name: name,
},
}
}

const createClaim = (name, amountOfMoneyToCollect) => {
return {
type: "CREATE_CLAIM",
payload: {
name: name,
amountOfMoneyToCollect: amountOfMoneyToCollect,
},
}
}

Note that we are just using an insurance company tracking their policies and claims as an example here to understand the Redux process.

Dispatch

The dispatch decides which reducer the action needs to be sent to. The action TYPE is what informs the dispatcher of which reducer it should route the action to.

Reducers

This covers the process of creating array based reducers. If you are looking object based reducers see here: Ncoughlin: React-Redux: Objected Based Reducers

The reducers are going to do different things with the action depending on what our intentions are.

If Correct Action Type, Return New Array

Each reducer is a function that takes two arguments, always in the same order. The first is the current list of actions that have already been saved with that type, and the second is the new action. The output of this reducer is a new array that includes the new action.

// reducers
const claimsHistory = (oldListOfClaims, action) => {
if (action.type === "CREATE_CLAIM") {
// we care about this action
return [...oldListOfClaims, action.payload]
}
}
ES2015 Array Shorthand …

The ... notation creates a new array starting with the named array, and then adds the additional items to the array.

Babel: Learn ES2015, Default + Rest + Spread

new array from shorthand

So we have checked to see if the action is the correct type of action to be sending to this reducer, if it is then we send the action to the repository of this type.

Additional Reducer Data Manipulation Strategies

Because it is important to always be sending a new array/object to the store instead of modifying the current one, the strategies we must use to manipulate the data are different from what you would first think. Review these tables for a list of strategies that create a new array/object and then perform the desired action.

Array Manipulation
BadGood
Removing an element from an arraystate.pop()state.filter(element => element !== 'hi')
Adding an element to an arraystate.push('hi')[...state, 'hi']
Replacing an element in an arraystate[0] = 'hi'state.map(el => el === 'hi' ? 'bye' : el)
Object Manipulation
BadGood
Updating a property in an objectstate.name = 'Sam'{...state, name: 'Sam'}
Adding a property to an objectstate.age = 30{...state, age: 30 }
Removing a property from an objectdelete state.name{...state, age: undefined }
""_.omit(state, 'age')

Return Original Array If Incorrect Action Type

Lastly if we have passed in the wrong type of action we want to simply return the list of claims as it was.

// reducers
const claimsHistory = (oldListOfClaims, action) => {
if (action.type === "CREATE_CLAIM") {
// we care about this action
return [...oldListOfClaims, action.payload]
}

// we don't care about this action.
return oldListOfClaims
}

Default Value For First Action

We need to set a default value for the old array in case this is the first action of its type, in which case requesting that array would return undefined.

// reducers
const claimsHistory = (oldListOfClaims = [], action) => {
if (action.type === "CREATE_CLAIM") {
// we care about this action
return [...oldListOfClaims, action.payload]
}

// we don't care about this action.
return oldListOfClaims
}

Full Reducers Example

Continuing with our example of creating reducers for an mock insurance company. Above we made the reducer that handles adding a claim to the claim list. Now let’s add several more examples.

Below we will also handle what is happening in our accounting department, whether we are gaining money for a new policy or paying out money for a claim. And also the ability to add or remove policies.

Note that in all these examples we are returning a new array. In reducers we never modify the existing array. We always return a new array.

// REDUCERS

// create an insurance claim
const claimsHistory = (oldListOfClaims = [], action) => {
if (action.type === "CREATE_CLAIM") {
// we care about this action
return [...oldListOfClaims, action.payload]
}

// we don't care about this action.
return oldListOfClaims
}

// does the action affect our money balance? Default balance of $100
const accounting = (currentBalance = 100, action) => {
if (action === "CREATE_CLAIM") {
return currentBalance - action.payload.amountOfMoneyToCollect
} else if (action.type === "CREATE_POLICY") {
return currentBalance + action.payload.amountOfMoneyToCollect
}

return bagOfMoney
}

// if new policy add to policy list
// if removing, create new list without payload.name
const policies = (listOfPolicies = [], action) => {
if (action.type === "CREATE_POLICY") {
return [...listOfPolicies, action.payload.name]
} else if (action.type === "DELETE_POLICY") {
return listOfPolicies.filter(name => name !== action.payload.name)
}

return listOfPolicies
}

State

An object that serves as the central repository of all data from the reducers.

Redux Store

Now that we have created all of our action schemas and our reducer functions, we tie all of these things together using a few Redux methods, to create the one all powerful object called store, where the current value of all of our states are stored inside of their objects (action schemas).

// wiring reducers together with store

// pull methods out of Redux library
const { createStore, combineReducers } = Redux

// combining reducers
const ourDepartments = combineReducers({
accounting: accounting,
claimsHistory: claimsHistory,
policies: policies,
})

// create store, pass in ourDepartments
const store = createStore(ourDepartments)

// store object now represents our entire Redux application

// now if we create an action
const action = createPolicy("Alex", 20)

// use Redux dispatch method to run action through reducers
store.dispatch(action)

console.log(store.getState())

data in store

Comments

Recent Work

Free desktop AI Chat client, designed for developers and businesses. Unlocks advanced model settings only available in the API. Includes quality of life features like custom syntax highlighting.

Learn More

BidBear

bidbear.io

Bidbear is a report automation tool. It downloads Amazon Seller and Advertising reports, daily, to a private database. It then merges and formats the data into beautiful, on demand, exportable performance reports.

Learn More