Basic understanding of Redux

Mohan Praneeth
AppyHigh Blog
Published in
6 min readJul 21, 2019

What is Redux?

Redux is a helper library to make state management easy in JS Apps. In this article we will only explore in relation to React JS. For those who do not understand “state” , it is a container for data that is used in a component , especially in Front-End technologies like ReactJs

Do we need Redux?

We do not actually need Redux to build an application, but if you want your application to be really scalable and simplify the states and props used large number of Components, you would definitely love Redux. And the time invested to learn Redux would be worth!

Basic terminologies and Understanding the flow

Some terms may be over-whelming at the start of your Redux journey, but be assured that they can be quickly grasped and in no time these terms are just some terms! Some degree of Familiarity with ReactJs is expected to understand the below concepts ;)

1. STORE:

In REDUX , we have a centralised state-management, we refer this as a store, which contains all states(UI & Data) that is required by all the components together.

State management in REDUX applications

2. REDUCER:

Do not get intimated by a Reducer — Think of it like the store manager for the central-store. To modify anything in the store we need to go via the store manager.

“Reducer is the only way we need to modify something in the store — that something is the states contained in the central store”

3. ACTIONS:

So now components want to modify the state which is contained by the central store? How do they do it??

“Think of Actions like the authorisation letters written to the store-manager(Reducer) to modify something in the store”

Actions contains {type: … , payload: ….} type is the name of action to be identified and payload is the data or information required to perform the action in the store

Data Flow in Redux:

Let’s get Coding!!

Step-1 : First things first — Import createStore from Redux

import { createStore } from 'redux';

Step-2: create a centralised store — which is a createStore function, upon invocation of this fn a redux store is created and assigned to a variable of store. Usually we do this code in index.js where we finally render all the Components. So that the central store is accessible to all components.

const store = createStore(rootReducer);
/* createStore function takes rootReducer as the argument - which contains all the reducers combined */

Step-3 : So we need to define rootReducer , which we are passing as argument as we have discussed imagine rootReducer as the store keeper of the store. So this rootReducer will accept two arguments —(state, actions) and returns the newState after the action is performed on the store

To keep our code more readable and understandable — it is advisable to make directory of reducers and have rootReducer file which should combine all the reducers.

initState = {
users : [{},{},{}]
songs : [{},{},{},{}]
}
const rootReducer = (state = initState, action) => /* Here rootReducer identifies the type of Action and performs the action on the central store */return state
};

Lets recap now — we have created a store & we have created a rootReducer which is the only way to modify the store. The reducer takes in actions to . modify the store states and return the new-state

Step-4 : So now lets see how to make the store accessible to all components

In Redux-React projects we have only central store, states are not declared in individual components, so in order to access the central store we need react-redux library function “Provider” which will wrap the App and connects the App to the store . Now the store is accessible to all components. We will see how to access in next step

import { Provider } from 'react-redux'; <...code />ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,document.getElementById('root'));

Step-5: how do we get the data from the store to the component?

To connect the central store to individual component we use the react-redux library and in particular the “connect” function which upon invocation returns a higher order component (HOC). This HOC will wrap the component to give the accessibility of the redux store

connect()
// this will return a HOC
HOC(<componentName>)
// this HOC will wrap the component to give access to the store
connect()(<componentName>) - final expression

Now inside the component we do not have individual states, so we get the data as “props” from a function called “mapStateToProps”, which state of the “store” as args and returns a props object . Inside this function we define what data we want to grab from the redux store state

import {connect} from 'react-redux'<...code />const mapStateToProps = (state)=>{
return {
songs : state.songs
}
}
/* now we can access the songs data within this component as this.props.songs */export default connect(mapStateToProps)(<componentName>)/* here we are accessing the central store state and grabbing the songs data and passing as props for this particular component */

Step-6 : what about changing the state (data) ? and updating the state in components

For this we need to dispatch actions to the reducer and the reducer will make the requested changes in the store state, once the state is updated in the central store the components will get updated props automatically and gets rendered

As in the previous step we have grabbed the desired state via props using mapStateToProps, we will use a similar approach to change the store state using the “actions” to be dispatched from within component. mapDispatchToProps function which accepts dispatch fn (available in redux) as args and returns an object which gets added to props. Now the function is available in the props to be called and will dispatch the action when invoked. We need to pass mapDispatchToProps in to connect as second parameter to access the store

const mapDispatchToProps = (dispatch)=>{
return{
deleteSong : function(id){
dispatch(action)
}}
}
export default connect(mapStateToProps, mapDispatchToProps )(<componentName>)/* the deleteSong function will now be available in the props of this component and can be invoked to make changed to the state */

We are trying to make the deleteSong function available to the props of this component, which when invoked will dispatch the relevant action to the reducer and store for action to be completed.

Step-7 what exactly is action?

So in the whole unidirectional data flow in redux — components dispatch actions which are taken care by the reducer and will be applied to the store.

Actions should essentially tell the reducer that , I am an action of this type(deleteSong) and i want to get this thing done on certain data(payload) in your store.

export default function deleteSong(id) {
return {
type: DELETE_SONG, payload : id
} }

Here the deleteSong function will return an object containing type and payload — which we essentially call an “action”

so coming back to the earlier code of mapDispatchToProps , we need to import this action and dispatch this action

import {deleteSong} from './actions'const mapDispatchToProps = (dispatch)=>{
return{
deleteSong : function(id){
dispatch(deleteSong)
}}
}
export default connect(mapStateToProps, mapDispatchToProps )(<componentName>)

We could also map many actions together like the code below using bindActionCreators function available in ‘redux’

import {bindActionCreators} from 'redux';const mapDispatchToProps = (dispatch)=>{
return bindActionCreators({deleteSong, addSong , ...}, dispatch);
}

Step -8 : How will the actions be handled?

Once the action is dispatched the reducer will now take care of the action. We have already create a rootReducer in step-3 , but did not give any functionality to it. But lets first understand what a reducer must do

  • Identify the what action is dispatched
  • perform the action on the state (logic of the action is coded in the reducer)
  • returns the new- state with updated data
initState = {
users : [{},{},{}]
songs : [{},{},{},{}]
}
const rootReducer = (state = initState, action) => {if (action.type === 'DELETE_SONG') {let newSongs = state.songs.filter();return {
...state,
songs: newSongs
}
}
return initState;};/* Usually there will be many actions to a reducer - so writing switch-case conditional statements is more readable */

Thanks for reading!!

--

--