Comments

Redux in 2020

Do you want an overview of Redux and why you should learn this smoking-hot library in 2020? If you answered “YES!“, then this article is for you! You should have some familiarity with both JavaScript and at least one front-end framework. Let’s begin!

Redux Background:

Dan Abramov, a Facebook Sofware Engineer, created Redux. He was also on the core team that developed React.js. It’s no wonder that he’s a well-regarded JavaScript superstar on the interwebs. He released Redux to the public on June 2, 2015, and it has since exploded in popularity. Dan also developed the incredible create-react-app, the most popular boilerplate for React.

A Foreword on the Difficulty Curve

When first starting out, I learning Redux is going to be painful and frustrating. BUT, after some experience, you’ll start to understand the terminology and how the pieces fit together. When you hit that point, the difficulty curve drops significantly! From here on, the concepts you learn will “click” and things should become a breeze.

Are you starting to worry yet? Fear not! I’m going to breakdown Redux in simple terms, leave out the rest, and do so without getting you confused!

The Problem With Most Redux Overviews

The complexity of Redux is not the core problem with most overviews. Redux is only 2kb, including its dependencies. Most beginners who set out to learn Redux quickly get overwhelmed by the plethora of associated libraries: React-Redux, Redux-Thunk, Redux-Saga, Redux-Promise, Recompose, Reselect, etc. In addition, there’s Routing, Authentication, Server-side rendering, Testing, and Bundling. This is overwhelming to tackle all at once! The correct way to master any subject is to learn the basics until you know it like the back of your hand. Only then should you move on to the next topic.

When I went back to college to study computer engineering after being out of high school for 8 years, I had to restart all the way back at intermediate algebra. I had done poorly in high school (I thought I was too cool for school) and assumed that I was stupid. But no! This time, I was determined to succeed. I studied for 6 hours a day, earning the highest grade in my class, then moved on to Calc I, Calc II, Calc III, Differential Equations, etc.

When I started taking the harder classes as a junior and senior, I noticed my classmates were struggling much more than I, even though they were fresh from high school. I realized that it was my solid foundation in the fundamentals that allowed me to soar. I ended up tutoring Calc, Physics, & Chemistry and graduated at the top of my class from the University of Florida.

Using this technique, you can apply the same approach to your career!

My Approach 

We’re going to forget all the associated libraries and fluff, and I’m going to teach you the bare minimum that you need to know. For a bird, learning to fly means attempting to flap their wings and falling from their nest. Once they make the long trip back up, its time to try again! Finally, once they learn to spread and flap their wings with proper form, they can leave the safety of the nest and sail the skies!

Humans learn the same way – one step at a time, and repetition, repetition, repetition! Effective learning isn’t about just reading and listening. Effective learning is mostly about practice!

What Is Redux?

Redux is a state management library for JavaScript apps. You delegate it to handle data inside of your applications. It was not made solely for React – you can use Redux in many other view libraries. In short, Redux makes the state changes in apps more predictable. The more predictable an app’s state, the easier it is to test. The easier an app is to test, the fewer bugs your app will contain. Do you like apps that work flawlessly or do you like apps that glitch and ruin the user experience? I think I know what your answer will be!

Why Learn Redux?

State management becomes a huge concern when applications become large and have lots of moving pieces. In these instances, the state is hard to manage and Redux provides a way to keep the state in one central location.

Another great reason to learn Redux is that many web-development positions require experience with Redux. Finally, I suggest you learn Redux because of the principles it teaches. You will learn novel ways of doing common things, making you a better engineer.

When Not to Use Redux?

You should not even consider using Redux for many applications. Dan Abramov even warns about introducing Redux too early in an app’s life-cycle. Here’s a non-extensive list of times when you should NOT use Redux:

  • You heard it’s the hot, new framework and you want to impress your friends
  • You’re still gaining experience with React or another framework
  • Your app consists of mostly simple actions, like UI changes
  • You haven’t first taken advantage of your framework’s native state management solution

Redux By Example

Below is a diagram of the Redux cycle. These terms describe what is happening inside of Redux.

If I give you definitions of each term without context, you will be very confused. That’s why I am going to explain each step with an analogy. This analogy will increase your comprehension of Action Creators, ActionsDispatch, Reducers, and the Store. At times, it’s going to be somewhat complicated. But, it’s going to give you a true-to-life understanding of each step. Are you still with me? Let’s go!

Insurance Company Analogy

You and I are going to create an insurance company. Along the way, you’ll learn how Redux and each of its parts work. How does an insurance company work? I’m so glad you asked!

Customers buy something called a policy for a set price. If something terrible happens to the customer, like they crash their car or fall off a ladder, they file a claim. Then, if the content of the claim is covered under the customer’s policy, the insurance company pays out a lump sum to the customer.

Policy – A contract between the customer and the insurance company. It states that if the customer gets sick or injured, they will receive x amount of money from the insurance company.

Claim – A form that the customer sends to the insurance company. It outlines the nature of the customer’s illness/injury, and how much compensation they expect to receive from the insurance company.

Insurance Company Workflow

Below is a schematic of our insurance company. Housed under the roof are the Claims, Policies, and Accounting departments. Let’s walk through what happens when a new customer signs up for a policy:

  1. First, the Customer fills out a new form with the insurance company.
  2. The customer cannot hand their form directly to a department, there needs to be a buffer. Instead, they walk up to the front desk and hand their form to an Insurance Agent.
  3. Then, the Insurance Agent makes copies of the form and sends one to each of the three insurance company’s departments: the Claims, Policies, and Accounting departments.

Registering a Form With the Policies Department

The Claims & Accounting departments don’t need a copy of the forms. The only department that would need a record of the form is the Policies department. Here is what happens internally when a form registers with the Policies department:

  • The Customer gives a new form to the Insurance Agent, who hands it off to the Policies department. This department maintains a list of all customers who hold an active policy.

  • The Policies department would accept this form, see that this customer, Angela, is trying to sign up for a new policy, and add them to the list containing John, Debbie, Stefanie, and Tyler.

  • Let’s make this a bit more complicated… let’s say that we have an Administration team at our company. This team consistently bothers the Policies Department by requesting a list of policyholders.  As I’m sure you can imagine, the Administration team eventually gets frustrated that they have to constantly badger the Policies department for its list. This is a problem.

Setting Up a Central Repository

To fix this issue, we’re going to change where the state is stored. Rather than each department maintaining its state, we’re going to store it all in one central repository, called Department Data, that is stored independently of the departments. Department Data will house ALL of our app’s data (a list of policyholders, an extensive list of claims, and the company’s account balance). Now, the Administration team can easily retrieve any department’s state by making a single request to the central repo, all without having to knock on the door of each department.

Updating the Central Repository

In our old model, each department held and updated its own state when a form was received. But how do we update the central repository when a department’s state changes? Let’s run through an example of a customer buying a new policy:

  1. The Insurance Agent makes copies of a form to hand off to the policies department
  2. The Insurance Agent retrieves the policy department’s state from the central repo
  3. The Insurance Agent passes both the form and state to the policies department
  4. The form is processed, the list of policies (state) is updated, and the policies department’ state is forwarded to the central repo

*The same flow is applied to every department.

Deep Dive Into Forms

Are you ready to dive deeper into the analogy? Put on your dive mask and let’s get to it!

Every form that gets filled out by a customer is going to have 2 fields: a ‘Type’ and a ‘Payload’ property. The form’s Type, positioned at the top, declares what the purpose of the form is. Then, the body (or Payload) of each form, describes what the form is doing.

For example, if a customer is trying to create a new claim, we might want the customer to give us their Name (so we can identify them) and the Amount (or how much money this customer is asking to be paid for the claim).

In total, our company needs 3 different types of forms:

  1. Create Policy: a form for a customer to create a policy —>  Type – “CREATE_POLICY”, Payload – { Name: James, Amount: $20 } 
  2. Create Claim: a form for a customer to create a claim  —>  Type – “CREATE_CLAIM”, Payload – { Name: Britney, Claim Amount: $400 } 
  3. Delete Policy: a form for a customer to delete their active policy  —>  Type – “DELETE_POLICY”, Payload – { Name: Britney }

How Claims History Department Processes a New Form

  1. The Insurance Agent gets a new form from a customer.
  2. Then, the Insurance Agent hands the form AND a list of all previous claims (from the central repository) to the Claims department.
  3. Then, the Claims department will look at the form’s Type.
  4. If the form’s Type is “CREATE_CLAIM”, the Claims department is going to pull the Payload off the form, add it to the list of claims, and forward the updated list of claims to the central repository.
  5. If the form’s Type is NOT “CREATE_CLAIM”, the Claims department is going to return the unchanged list of claims.

How Policies Department Processes a New Form

  1. The Insurance Agent gets a new form from a customer.
  2. Then, the Insurance Agent hands the form AND a list of everyone who holds a policy (from the central repository) to the Policies department.
  3. Then, the Policies department is going to look at the form’s Type.
  4. If the form’s Type is NEITHER “CREATE_POLICY” NOR “DELETE_POLICY”, return the unchanged list of policies.
  5. If the form’s Type is “DELETE_POLICY”, the Policies department is going to pull the ‘Name’ property from the Payload of the form. Then, it will find the matching name from the list of policies, delete the Name, and forward the updated list to the central repository.
  6. If the form’s Type is “CREATE_POLICY”, the Policies department is going to pull the Payload off the form. Then, it will find the ‘Name’ property in the Payload, add it to the list of policies, and forward the updated list to the central repository.

How Accounting Department Processes a New Form

  1. The Insurance Agent gets a new form from a customer.
  2. Then, the Insurance Agent hands the form AND and the account balance (from the central repository) to the Accounting department.
  3. Then, the Accounting department is going to look at the form’s Type.
  4. If the form’s Type is “CREATE_CLAIM”, the Accounting department is going to pull the ‘Claim Amount‘ property from the Payload of the form. Then, the claim amount ($50 in this case) from the company’s balance is sent off to the customer who filed the claim. The company’s previous balance ($500) – Claim Amount ($50) = $450 = New account balance. Finally, the new account balance is forwarded to the central repository.
  5. If the form’s Type is NOT “CREATE_CLAIM”, but it IS “CREATE_POLICY”, the Accounting department is going to pull the ‘Policy Amount‘ property from the Payload of the form ($150 in this case), add it to the account balance ($500) + $150 = $650, and forward the new account balance to the central repository.
  6. In the final case, if the form’s Type is NEITHER “CREATE_CLAIM” NOR “CREATE_POLICY”, just return the unchanged account balance ($100).

Mapping the Analogy to Redux

Are you still with me? Good! Now that I’ve finished explaining this rather long analogy, we’re going to map it to the world of Redux. Below is our original diagram with each step of our analogy mapped up to the Redux Cycle.

Action Creators

Every flow in our insurance company example started with a customer dropping a form off. This step is identical to an Action Creator in Redux.

An action creator is a function that is going to create, or return, a plain JavaScript object. Its ONLY purpose is to create the action.

Actions

The insurance forms contained information describing how to change some data within our insurance company. The form itself had a ‘type’ and a ‘payload’. This step maps up to an action in Redux.

An action is a plain JavaScript object that an action creator returns. An action has a ‘type‘ property and a ‘payload’ property, identical to our insurance forms. The ‘type’ property describes some change that we want to make inside of our data. The ‘payload’ property describes some context around the change that we want to make.

In our insurance company example, after the customer gave the insurance agent a form, the insurance agent made copies of it and handed it off to each department. It would then be up to the department to look at the details of that form and decide how to change the data that the department was maintaining. The EXACT SAME thing is true in Redux. The purpose of an action is to describe some change that we want to make to the data inside of our application.

Dispatch

After the customer dropped off the form, it was given to the Insurance Agent. The Insurance Agent made copies of the form and handed one off to each department. This is the same function of dispatch in Redux.

The dispatch function receives an action, makes copies of that object, then passes it to a bunch of different places inside of our application.

Reducers

In our insurance company, each department had its own data: a list of policies, claims, and the account balance. Each department WAS its own piece of data in our app. The same is true of reducers in Redux.

reducer is a function that is responsible for receiving an action, and some existing amount of data. Then it’s going to process that action, make changes to the data if required, then return it, so that it can be centralized in the store (definition in the next section).

It’s the exact same thing that a department was doing. Remember, a department took in a form, looked at the type of the form, then decided how to update its data based on that type. A reducer is going to do the same thing: receive an action, inspect its ‘type’, and update its data based on the type. Click here for a more in-depth discussion about the Redux reducer.

Store

When a department was done processing a form, it spat out a list of data and forwarded it to the insurance company’s central repository of data (labeled ‘Department Data’). The central repository is identical to the Store in Redux.

The Redux store is a central repository of all the information that has been created by our reducers (departments). All the information gets consolidated inside the store so that the framework using Redux can easily reach into it and get access to all the data inside of our application. Because of this, our application doesn’t have to go to each separate reducer (department) and ask for the current state (ex. list of policies).

Insurance Company Redux Code Example

Do you want to finally write some code? I know you do! We’re going to code our entire insurance company, step by step, using Redux.  Since CodePen allows us to use Redux independently from a framework, I’ll be using it to code our examples. Since we’re using pure Redux, there won’t be any UI to view. Instead, I’ll be posting screenshots of the data that’s output to the console.

If you want to see my completed CodePen example, click here.

Coding the Action Creators and Actions

First, we’re going to create the action creators and actions. Remember, an action creator is a function that returns a plain JavaScript object (or the action). The action is just like our form. It contains a type, that describes the purpose of the form, and a payload, that describes what the form is doing.

We’re going to code one action creator for each different type of action that we have inside of our app.

  • An action creator that returns an action of type CREATE_POLICY:
// People dropping off a form (Action Creators)
const createPolicy = (name, costOfPolicy) => {
	return { // Action (a form in our analogy)
		type: 'CREATE_POLICY',
		payload: {
			name, // Johnny
			costOfPolicy // $150
		}
	}
}
  • An action creator that returns an action of type DELETE_POLICY:
const deletePolicy = (name) => {
	return { // Action (a form in our analogy)
		type: 'DELETE_POLICY',
		payload: {
			name // Johnny
		}
	}
}
  • An action creator that returns an action of type CREATE_CLAIM:
const createClaim = (name, claimAmount) => {
	return { // Action (a form in our analogy)
		type: 'CREATE_CLAIM',
		payload: {
			name, // Johnny
			claimAmount // $200
		}
	}
}

Compare these three action creators. Don’t they look almost identical? They all return a JavaScript object that contains a type and a payload. Just about every single action creator that you are ever going to write is going to be identical to this. There may be small variations, but they’ll all be very similar. The complicated part of Redux isn’t syntactical. Instead, most people get tripped up on understanding how the Redux cycle works – which is why I hammered you with this analogy.

Coding the Reducers

Each one of our reducers is going to be called by an action (or a form) that was created by an action creator. The reducer is then going to inspect that action (or form) and decide whether or not it needs to modify its data. Remember, we had said that in order for the Administration to access the data produced by our departments, we were going to move our data to a central repository. Then, only when we had a form to pass to a department would we take that department’s piece of data, inside the central repository, and pass it into that department. This will all become more clear when we code the reducers.

Every reducer is going to be a function. It always gets two arguments that are always passed in the exact same order. The first argument is the initial state (or existing little slice of data from our central repository that belongs to this department). The second argument is always an action (or form, from our example).

These reducers are going to be modeled on the diagrams that show how the departments process forms. We’re going to code one reducer for each different department inside of our company.

  • reducer that corresponds to the Claims History department processing a form:
// We must initialize the listOfClaims to an empty array, since no claims have been added yet
const claimsHistory = (listOfClaims = [], action) => {
	if (action.type === 'CREATE_CLAIM') {
		// Redux assumes that you NEVER mutate the objects it gives to you in the reducer. Every single time, you must return the new state object.
		// ex. return listOfClaims.push(action.payload) --> WRONG: this mutates the state
		// Instead, flatten listOfClaims array, add the new claim to it, and return the new list to Redux store
		return [...listOfClaims, action.payload]
	}
	
	// Return unchanged list of claims
	return listOfClaims
}
  • reducer that corresponds to the Policies department processing a form:
// We must initialize the listOfPolicies to an empty array, since no policies have been purchased yet
const policies = (listOfPolicies = [], action) => {
	if (action.type === 'CREATE_POLICY') {
		// Flatten listOfPolicies array, add the name of the new customer to it, and return the new list to Redux store
		return [...listOfPolicies, action.payload.name]
	} else if (action.type === 'DELETE_POLICY') {
		// The filter function will create a new policies array with all names NOT matching the name to delete. Return new list to Redux store 
		return listOfPolicies.filter(name => name !== action.payload.name)
	}
	
	// Return unchanged list of policies
	return listOfPolicies
}
  • reducer that corresponds to the Accounting department processing a form:
// We must initialize the company's balance. Let's set to $500, since that's what our example used.
const accounting = (balance = 500, action) => {
	if (action.type === 'CREATE_CLAIM') {
		// Return balance - claim amount, and return to Redux store
		return balance - action.payload.claimAmount
	} else if (action.type === 'CREATE_POLICY') {
		// Return balance + cost of policy, and return to Redux store
		return balance + action.payload.costOfPolicy
	}
	
	// Return unchanged account balance
	return balance
}

Coding the Dispatch and Store

Now that we’ve coded our action creatorsactions, and reducers, we’re going to wire them together into a single object called the store. The store in Redux is the assembly of a collection of different reducers and action creators.

If I type the following code in my CodePen project:

console.log(Redux)

We’ll see the Redux library output to the console:

Do you see the combineReducers and createStore functions in the Redux object above? They come bundled with Redux. We’re going to use these functions in our next examples.

Wiring Together the Reducers

To wire together all of our reducers, we’re going to use the combineReducers function from Redux.

const ourDepartments = combineReducers({
	// Here, we're passing in all of our reducer's functions
	claimsHistory, 
	policies, 
	accounting
})

Coding the Store

The Store object represents our entire Redux application. It contains references to all of our reducers and the state (data) of those reducers.

// Now, we're passing in ourDepartments (the combination of our reducers) to create our Store
const store = createStore(ourDepartments)

If I type the following code in my CodePen project:

console.log(store)

We’ll see the store object output to the console:

If I type the store’s getState() function in my CodePen project, it should show an empty store, since we haven’t yet called dispatch with an action. The getState() function gives us access to Redux‘s current state.

console.log(store.getState())

Console output:

Do you notice how accounting has a $500 balance, even though we haven’t yet dispatched an action? Remember how we initialized the account balance to $500 in our accounting reducer? That’s why!

Coding Dispatch

The dispatch function is just like the Insurance Agent. We’re going to pass an action (Form) to the dispatch (Insurance Agent) function. JUST LIKE the Insurance Agent brought a copy of the Form to every department in the insurance company, dispatch is going to send the action to every reducer inside the Redux application.

Since we must pass in an action (which are returned from action creators) we must first call an action creator.

const action = createPolicy('Johnny', 150)

If we print the action to the console, we can see the type and the payload:

Now we’re going to take that action, and pass it into dispatch:

store.dispatch(action)

So, as soon as we call dispatch, each of our reducer functions receives and processes that action. If the action is relevant to that reducer, then it changes the state inside of the store.

If I run the store’s getState function again, the store should show that it added ‘Johnny’ to the list of policies, and added $150 to the accounting balance. Let’s check:
store.getState()  

Don’t you love it when things just WORK?

Coding a Few More Examples

Now we can call all of our action creators, and pass the action that gets returned into dispatch. That’s going to incrementally modify how the state of our company looks (that is contained in the store). Let’s try doing a few more examples. This time, however, we’re going to refactor to pass the action creators directly into dispatch (since they return an action anyways):

store.dispatch(createPolicy('Johnny', 150))
store.dispatch(createPolicy('Este', 185))
store.dispatch(createPolicy('David', 115))
console.log(store.getState())

If we look at the store now, we should see that a policy has been created for ‘Johnny’, ‘Este’, and ‘David’. In addition, their policy amounts ($150 + $185 + $115) should have been added to the original $500 balance (totaling $950):

Now, let’s create a claim and delete a policy:

store.dispatch(createClaim('Johnny', 90))
store.dispatch(deletePolicy('David'))
console.log(store.getState())

Now, the store should reflect that a claim has been added for ‘Johnny’. So the claimsHistory array should have added the claim’s name and claimAmountThe accounting balance should also reflect ‘Johnny’s’ $90 claim amount subtracted from its balance ($950 – $90 = $860). Finally, ‘David’ should have been deleted from the policies array.

 

Redux Trends

Redux Prevalence

About 60% of all React apps are built with Redux.  In turn, we can assume that 60% of React positions will require Redux knowledge. In my experience working as a freelance developer for multiple companies, I can verify that 60% is RIGHT ON THE MONEY. So, especially if you are a React developer, it is invaluable to your career to jump on the Redux train!!

NPM Search Trends

Let’s dissect the popularity of the Redux package downloads in the last 2 years. From its inception, it quite rapidly increased in popularity until it recessed in December 2018. It recovered a month later and hit its peak popularity in March 2019, before pulling back a bit.  Slowly, it gained traction before recessing again in December 2019 (could be a December pullback pattern?).  It’s since gained more traction and should surpass its peak in a matter of months.

Redux Job Trends

According to https://www.itjobswatch.co.uk/,the following chart shows the job postings citing Redux as a percentage of all IT jobs advertised.

Do you see the relatively linear ramp up from 2016 through now? Redux is on fire. ~1.4% may not seem like a lot, but keep in mind that this chart takes into consideration ALL Information Technology jobs. IT is a huge pie, and software development is a small slice.

 

Recap

Let’s recap what you’ve learned in this article:

  • When we want to change state in Redux, we call an action creator.
  • An action creator is going to produce an action, which is a normal JavaScript object with type and payload properties.
  • An action is a normal JavaScript object and describes how we want to change data in our app (usually has ‘type’ and ‘payload’ properties)
  • The action gets fed to the dispatch function which, in turn, is going to make copies of the action object and feed one to each of our different reducers.
  • The reducers are going to run and process the actions, modify its data, and return a new state object.
  • The new state object gets forwarded to the store, then we wait until we need to update state again to restart the cycle.
  • 60% of all React apps are built with Redux.
  • Employers are increasingly looking for talent with Redux experience.

 

Do you want to become a React master? If so, check out Mosh’s React course. It’s the best React course out there! And if you liked this article, share it with others as well!

I’m a scholar and musician. You can usually find me coding away at my desk 💻 or writing/recording music 🎸🎧,
Tags: , , ,

Leave a Reply

Connect with Me
  • Categories
  • Popular Posts