Giter Site home page Giter Site logo

redux-flow-dumbo-web-career-040119's Introduction

Using Pure Functions to Update Application State

Objectives:

In this lesson, you will learn the following:

  • Learn how pure functions update our application state.
  • Learn the fundamentals of the redux flow.
  • Learn how to adhere to the constraints of a pure function.

Review

So far we know that all of our state is in a JavaScript object, and that our actions are in another JavaScript object called an action. Somehow the action updates our state.

Let's take a look at an example:

let state = {count: 0}
let action = {type: 'INCREASE_COUNT'}

Somehow I want to send this action to the state so that at the end our state is updated to look like the following: state -> {count: 1}.

But how??

Functions to the Rescue

This seems easy enough. Why not just write a function that takes in our previous state, takes in our action, and depending on that action produces a new state. Here's what it could look like:

function changeState(state, action) {
  if (action.type === 'INCREASE_COUNT') {
    return {count: state.count + 1 }
  }
}

That's pretty straightforward code. If the action's type property is the String 'INCREASE_COUNT' then go ahead and increment and return the new state.

The important piece of information we looked at to determine how to change the state was action.type. Actions always need a type property so the function knows what to do. If you can imagine a whole bunch of different actions that change the state in different ways, 'DECREASE_COUNT', 'INCREASE_COUNT_BY_TEN' and so on, it shouldn't be hard to see how that code could become very messy with a bunch of ifs and else ifs. Instead, it is customary to use a switch case statement.

function changeState(state, action){
  switch (action.type) {
    case 'INCREASE_COUNT':
      return {count: state.count + 1}
  }
}

This makes it very explicit and clear that action.type is the information we are switching on to make our decision on how to change the state.

We'll talk about this more in-depth later, but it is important that when we change the state we never return null or undefined. We'll cover this by adding a default case to our function.

function changeState(state, action){
  switch (action.type) {
    case 'INCREASE_COUNT':
      return {count: state.count + 1}
    default:
      return state;
  }
}

This way, no matter what, when accessing the Redux state we'll always get some form of the state back.

let state = {count: 0}
let action = {type: 'INCREASE_COUNT'}

changeState(state, action)
// => {count: 1}

Ok, so if you copy and paste that code into a JavaScript console, you'll see that the function works just as we'd expect. The state and action are passed to our changeState function, which hits the 'INCREASE_COUNT' case statement. Then it takes the state's count of zero, adds one to it, and returns a new object {count: 1}.

Now let's have this function respond to another action, decrease count. Give it a shot, the answer is below.

function changeState(state, action){	  
  switch (action.type) {
    case 'INCREASE_COUNT':
      return {count: state.count + 1}
    case 'DECREASE_COUNT':
      return {count: state.count - 1}
    default:
      return state;
  }
}

let state = {count: 0}

changeState(state, {type: 'INCREASE_COUNT'})
// => {count: 1}

changeState(state, {type: 'DECREASE_COUNT'})
// => {count: -1}

Ok! That my friends, is the crux of redux. To summarize:

Action -> Function -> Updated State

And let's give this function a name. Because it is combining two pieces of information, our current state and an action, reducing this combination into one value, we'll say that it reduces the two into one updated state. For this reason, we call this function a reducer:

Action -> Reducer -> Updated State

As you learn more about redux, things may become more complex. Just remember that at the core of redux is always this flow. An action gets sent to a reducer which then updates the state of the application.

TWIST

You may notice a problem. While we can call the changeState reducer to increase the count from zero to one, if we call change state again we keep returning a count of one. In other words, we are not persisting this change of state. We'll tackle how this works in an upcoming section.

Reducers are pure functions

function reducer(state, action){	  
  switch (action.type) {
    case 'INCREASE_COUNT':
      return {count: state.count + 1}
    case 'DECREASE_COUNT':
      return {count: state.count - 1}
    default:
      return state;
  }
}

An important thing to note about reducers is that they are pure functions. Let's remember the characteristics of pure functions:

  1. Pure functions are only determined by their input values

  2. Pure Functions have no side effects. By this we mean pure functions do not have any effect outside of the function. They only return a value.

Note: The reason we like pure functions so much is because if a function has no effect outside of the object, and if the function always returns the same value given a specific input, this means that our functions become really predictable. In addition, the lack of side effects means that the functions are also contained, and can be used safely without affecting the rest of your application.

Let's take these two characteristics of pure functions in turn, and ensure that we are adhering to them here.

Ok, so the first characteristic of pure functions means that given the same input of the function, I will always receive the same output from that function. That seems to hold, given a specific state object like {count: 2} and an action object like {type: 'DECREASE_COUNT'} - will I always get back the same value? Yes. Given those two arguments, the output will always be {count: 1}.

As for the 'no side effects' characteristic, there's something pretty subtle going on in our reducer. The object returned is not the same object that is passed as an argument to the function, but rather a new object that is constructed each time our reducer is called. Do you see why? Take a close look at the line that says return {count: state.count + 1}. This line is constructing a new JavaScript object and setting its count attribute to equal the previous state's count plus one. So we adhere to the constraints of a pure function by not changing any value that is defined outside of the function.

Summary

  1. We hold our application's state in one plain old JavaScript object, and we update that state by passing both an action and the old state to our reducer. Our reducer returns to us our new state.
  2. So to change our state we (1) create an action (an action is just a plain object with a type key); and (2) pass the action as an argument when we call the reducer (which is just a function with a switch/case statement). This produces a new state.
  3. Our reducer is a pure function which means that given the same arguments of state and action, it will always produce the same new state. Also it means that our reducer never updates the previous state, but rather creates a new state object.

View Redux Flow on Learn.co and start learning to code for free.

redux-flow-dumbo-web-career-040119's People

Contributors

gj avatar maxwellbenton avatar bal360 avatar crwhitesides avatar ihollander avatar jeffkatzy avatar mhnguyen289 avatar

Watchers

Mar avatar Kaitlin Vignali avatar Mohawk Greene avatar  avatar Joe Cardarelli avatar The Learn Team avatar  avatar Liz Burton avatar Matt avatar Alex Griffith avatar  avatar Amanda D'Avria avatar  avatar Ahmed avatar Nicole Kroese  avatar Dominique De León avatar  avatar Vicki Aubin avatar  avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.