The Final Project

Nate Nelson
3 min readJun 10, 2021

--

Who’d a thunk?

I suppose it is a bit strange of me to get giddy over state management; but you know what, I'm just gonna lean into it hard! I love Redux! You can teleport through the user experience, everything is neatly tucked away with it’s own job and the dev-tools for it are just spot on!

But that being said, out of the box, it can be quite the hassle to set up with all of it boiler-plate code. Well fortunately I discovered this sweet little package called…. drumroll please … @reduxjs/toolkit! (Don’t know why the developers thought it be cool to prefix it with the @ sign, but what evs).

This was particularly useful for my final project at Flatiron school.

— find me at github.com/Naternelson

Its an interface to upload data and have your data run through a modeling software (modeling software not included).

So the major hurtle with Redux is that you have to type out a lot, and remember the rules of immutability.

> Sidebar, “immutability” means that the same object in the same memory cannot change. It is immutable. Certain languages are naturally immutable, JS is not, particularly JS Objects.

Redux reducers may seem like they’re intended to change the state of the store, but in actuality they constantly copy the store into a new object and present that store as the current one. But all those previous instances of the store are not loss to us, they live in on memory and we can use that to time travel through.

## ActionCreators

One of the beauties is action creator or CreateAction fn. It is a higher order function that accepts a single argument for the action type and turns this:

const someAction = {
type: "someAction",
payload: {data}
}

Which you would have to duplicate over and over again for each action.

Into this:

import { createAction } from '@reduxjs/toolkit'
const someAction = createAction("someAction")
' and to Deploy it
dispatch(someAction(payload))

One action for one reducer, sounds elegant no?

## Slice

But probably the most delicious aspect of @reduxjs/toolkit is their slice method, one method to rule them all! Check out how I used it in my project:

import {createSlice} from '@reduxjs/toolkit'
import { apiCallBegan } from '../middleware/middleware-actions'
const statusTypes = {LOADING: "loading", LOADED: "loaded", ERRORSTATUS: "error"}
const {LOADING, LOADED, ERRORSTATUS} = statusTypes
//Slice
const slice = createSlice({
name: "projects",
initialState: {
status: LOADING,
order: [],
data: {},
},
reducers: {
projectsAdded: (state, action) => {
state.data = {}
state.order = []
for(let i of action.payload.projects.data){
state.data[i.id] = i.attributes
state.data[i.id].loadStatus = LOADED
state.order.push(i.id)
}
state.status = LOADED
},
projectDeleted: (state, action) => {
const id = action.payload.project.id
delete state.data[action.payload.project.id]
state.order = state.order.filter(i => i.toString() !== id.toString())state.status = LOADED
},
projectUpdated: (state, action) => {
const id = action.payload.project.data.id
const arrIndex = state.order.indexOf(id)
state.data[id] = action.payload.project.data.attributes
if(arrIndex === -1) state.order.push(id)
state.data[id].loadStatus = LOADED
},
inError: (state, action) => {
state.status = ERRORSTATUS
state.error = action.payload.error
}
}
})
export const {projectsAdded, projectDeleted, projectUpdated} = slice.actions
const {inError, projectsLoading} = slice.actions
export default slice.reducer
export const loadProjects = () => apiCallBegan({
url: "/projects",
method: 'get',
onStart: projectsLoading.type,
onSuccess: projectsAdded.type,
onError: inError.type
})
export const patchProject = data => apiCallBegan({
url: `/projects/${data.id}`,
method: 'patch',
data,
onSuccess: projectUpdated.type,
onError: inError.type
})
export const loadProject = data => apiCallBegan({
url: `/projects/${data.id}`,
method: 'get',
data: data,
onStart: projectsLoading.type,
onSuccess: projectUpdated.type,
onError: inError.type
})
export const deleteProject = data => apiCallBegan({
url: `/projects/${data.id}`,
method: 'delete',
onSuccess: projectDeleted.type,
onError: inError.type
})

Ok so that’s a lot, but we can break it down simple!

If we look at the slice variable we see that we’re only creating three objects, a name, an initial state and reducers. The magic of these reducers is that they automatically map to actions! In fact the slice can return actions, and when we can the reducer with a provided action, it’ll run the function associated with its reducer. Very neat indeed.

Also you may be tearing your hair out ’cause it looks like I’m mutilating the poor state, for shame! Actually I’m not, @reduxjs/toolkit actually passes the function to immer. Immer is a JS library that’s all about preserving immutibility. It’s smart enough to see what changes we are making to this Pseudo Store State and return a new Store with those changes, all without having to do any destructuring, or Object.assign -ing. So fancy!

It’s been a really really good time learning from Flatiron, I can only hope it continues to grow and get better from here!

--

--

Nate Nelson
Nate Nelson

Responses (1)