Redux Fundamentals

Redux Fundamentals

Before we learn what redux is, we must understand what is state in javascript applications. In concrete terms state is javascript object

State of the app is plain javascript object.

const state = {
    isLoggedIn:true
}

how to reliably keep track of these state changes ? An unrelated piece of logic could mutate the state changing the behaviour of an app.

Anyone with little understanding of react should not be surprised with the term state. I guess you already wrote some stateful React components like shown below:

import React from 'react'

class ExampleComponent extends React.Component{
        state={
            contact:[
                {name:"John Doe", age:34, id:1}
                {name:"Patrick elm", age:35, id:2}
            ]
        };
}

render(){
        const {contacts} = this.state
        return(
            <ul> {contacts.map(contact => <li key={contact.id}>{contact.name}, {contact.age}</li>)}</ul>;
        )
    }
}

In a React component the state holds data which can be rendered to the user. The state could change in response to the user actions.

Typical application is full of state, for example, the state is:

  1. what the users sees on the webpage (data)
  2. Items selected on the page
  3. erros to show to the user
  4. data we fetch from the API

what problem does redux solve ?

Redux help you deal with shared state management.

Redux is more helpful when,

  1. large amounts of application state that are needed to be managed in many places in the app
  2. The app state is updated frequently and the logic to update that state may be complex.

What is redux ?

Redux is package that create global state which can be shared between components and no parents / child relationship required.

when using redux you don't actually change the state, you create updated copy of the state.

There are few things regarding redux that we need to learn such as the redux setup and pattern it uses to update and retrieve state that. There are few concepts we need to understand to get started with redux.

  • Stores
  • Reducers
  • Actions

Redux Store

Redux places all of component's state in once central location. The location in which we store the state is called store.

You can think of store as a global javascript object which can be accessed by all our components. Javascript object is immutable and cannot be changed directly, but a copy of its updated properties can be returned. This is useful to see how our apps looks at particular point in time as the state changes.

Redux Reducer

A reducer is a function that takes two arguments and return the app's current state. Both the arguments it takes are javascript object

  1. Current state
  2. An Action
const initialState = {
    count: 0
}

const reducer = (state = initialState, action) => {
    return state
}

Let's first create a simple functional counter component and then add redux functionality to it

App.js

import './App.css';
import Counter from './component/counter'

const App = () => {
  return (
    <div className="App">
      <Counter />
    </div>
  );
}

export default App;

counter.js

import React, {useState} from 'react'
import { connect } from 'react-redux'
import '../App.css'

const Counter = (props) => {
        const [counter, setCounter] = useState(0)

        const increment = () => {
        setCounter(prevCounter => prevCounter + 1)
    }

    const decrement = () => {
        setCounter(prevCounter => prevCounter - 1)
    }

    return (
        <div className="App">
            <h2>Counter</h2>
            <div className="counter">
                <button onClick={decrement}>-</button>
                <span className="counter">{counter}</span>
                <button onClick={increment}>+</button>
            </div>
        </div>
    )
}

export default Counter

Output

chrome-capture (1).gif

Now that we have written stateful component, let's see how we can add redux to the app and I will explain all of the redux code.

Let's put our understading of redux in practice

First to create the store which holds all the state tree we need to call import {createStore} from 'redux' to use createStore from redux library.

Set your app's current state before the reducer and then set it as the argument's default as shown earlier.

we integrate it into our store and our file looks like below.

import './App.css';
import Counter from './component/counter'
import { createStore } from 'redux'

const initialState = {
  count: 0
};

const reducer = (state = initialState, action) => {
      return state
  }
}

const store = createStore(reducer);

export default App;

Since we are using reducer as argument in createStore, it will be called couple of times:

  1. Once on initialization
  2. And every time an action is dispatched.

This leads us to learn the next term of redux - redux actions.

Redux Actions

An action is plain javascript object that has two properties: type and payload. Action is an event that describes something that happens in our app based on user input and triggers update in the state.

{
    type: 'ADD TITLE'
    payload: { id:1, title:'Redux Reducer'}
}

All the object is describing is that our app is updating via the type property, while containing data that we would like to add into our main state object.

To "call" this action, we need to use our store's dispatch method as

store.dispatch({type:'ADD_TITLE', payload:{id:1, title:"Redux Action"}})

When dispatch is called, this will run reducer function that we created earlier. our action is passed as second argument in reducer function, and we can then determing how we want to update our state based off what action was specified:

Connecting Redux to React

In order to access our store's global state within React components, we must download another package - react-redux:

react-redux provides a component called Provider and a function called connect.

The Provider component is wrapped aroung the react's root app component to pass our store as props to provide it to all component within our app:

App.js

import './App.css';
import Counter from './component/counter'
import { createStore } from 'redux'
import {Provider} from 'react-redux'

const initialState = {
  count: 0
};

function reducer(state = initialState, action) {

  switch (action.type) {
    case "INCREMENT":
      return {
        count: state.count + 1
      };
    case "DECREMENT":
      return {
        count: state.count - 1
      }
    default:
      return state
  }
}

const store = createStore(reducer);
console.log('The store is: ', store);

const App = () => {
  return (
    <Provider store={store}>
      <Counter />
    </Provider>
  );
}

export default App;

Inside counter.js, import connect from react-redux.

Instead of exporting our Counter component, we will export it with connect function.

counter.js

import React from 'react'
import { connect } from 'react-redux'
import '../App.css'

const Counter = (props) => {

    const increment = () => {
        props.dispatch({type:"INCREMENT"})
    }

    const decrement = () => {
        props.dispatch({type:"DECREMENT"})
    }

    return (
        <div className="App">
            <h2>Counter</h2>
            <div className="counter">
                <button onClick={decrement}>-</button>
                <span className="counter">{props.count}</span>
                <button onClick={increment}>+</button>
            </div>
        </div>
    )
}

const mapStateToProps = (state) => ({
    count: state.count
})

export default connect(mapStateToProps)(Counter)

The connect function takes another function as argument: mapStateToProps.

mapStateToProps determines what state from the store we want to pull into our component. In our case we are specifying to only pull our count property.

Once it is passed through to connect shown on the last line of counter.js file, it provides its connected component with the data from the store as props and access the count property like {props.count}.

Dispatch Action

Our component will recieve dispatch by default i.e when we do not supply a second parameter (mapStateToDispatch) to connect() like we did in our counter.js file above.

when we console.log(props); we can see props is an object with property count and dispatch function.

Screenshot (3).png

Running our above two files App.js and counter.js which has redux functionality we get the same output.

chrome-capture (2).gif

Thank you for reading. I hope the article was helpful.