Open In App

What Is Redux Change of State ?

Last Updated : 30 Dec, 2022
Improve
Improve
Like Article
Like
Save
Share
Report

Before going to the topic “Redux Change of State” we should look at the question “What is Redux?”.

"A Predictable State Container for JS Apps"

In other words, Redux is a pattern-based library that is used to manage and update the application state.  For managing and updating the application state Redux used events known as “action”.

Redux has some properties which make it popular some of them are described below:

  • Redux has the predictable property means it can run in different environments like the client, server, and native.
  • Redux Centralized the application state from which you can easily perform actions like undo, redo, state persistence, and many more.
  • Redux also has the property of debugging. In other words, Redux has Redux Devtools which make applications easily debuggable like when, where, why, and how your application state is changed.
  • Also Redux has the property of flexibility means it can work on any type of UI layer.

Let’s take an example to understand redux easily. Let’s imagine an application like a food app where we can manage the recipe using the Redux Store. For managing the recipe in the application we have some basic methods which help us to do so like:

We have a single store to manage the whole state of the application. Also, actions method to make necessary changes, we want to do. Reducers are like safety guards that know how to mutate state based on the requested action. And at least middleware is used to handle the task performed in the application.

REDUX OVERVIEW

As earlier as time spend the application grows at a large level. At this time management of the state and debugging the state is a very huge task for the application. It is also a challenge to manage the state and find where and when the state of the application is changed. Sometimes when the client calls some API or do changes to some data it turns some updates on the state of the application. So, for this, we need a model or management system which tracks the state of the application. For this Redux has been used because Redux is the state predictable container. For providing this service Redux used many components which are described below:

  •  Store
  •  Reducer
  •  Action

1. Redux Store: In Redux, the Redux store is the main component(first fundamental principle) of the Redux. Because all the things maintain the in the application by the Redux store. Redux store is a single store that stores the all state of the application and data. Any change which is happened in the Redux store is reflected in the whole application.  So for making the necessary changes in the state we do the following steps:

Step 1: Store The Application State 

The working of the store is:

  • First of all, the Redux store gets information about the application state.
  • Then it stores the change that happens in the state.
  • After this store changes the necessary changes in the state of the application.

CHANGE OF STATE

The function described in the Redux State which helps us in state management are given below:

  • getState() is the function used for getting information about the current state of the application.
  • For updating the state Redux is use dispatch(action). This is the one function used for making updates in the application. 
  • After this Store listens to the changes in the state. For this Redux used subscribe (listener) which sees the changes and updated state.

Now we are able to store the current state of the application. Next, we have to update the state for the next changes occurred in the state of the application.

Step 2: Updating the state of the application. For making the necessary changes or we can say for making the updates in the state of the application, we use an action.  Action is the main component of Redux because it has a special property known as type property which helps Redux to know about the changes that going to happen in the state of the application. So for this, we can say that Action has a descriptive property type.

For example, let have to design the bookstore application. Then user wants to add a book to the store. For we use the action function for making changes in the store. Action call the type property as given below: 

{ type: "ADD_BOOK" }

For this, we use the store.dispatch() function. That function is used by the library for accepting the action to perform in the state. This is the 2nd principle of the Redux fundamentals.

Now by all of this, we are able to make the update in the state of the application. Now we use the function for making the actually update by using these actions.

Step 3: Make changes by reducers. For making the changes in the state of applications, we use the pure function. These functions used the current state as a parameter and action to do changes. And after this return the updated state of the application. These functions are known as Reducers.  These are the function which doesn’t manipulate the state of the application while they make changes in the new object. From this, we are able to manage them or keep track of the changes in the state of the application. The main work of the reducers is that collect some values, reduce them to an updated state and then return it.

So after all, we are able to make changes to the application. And also keep track of every state with the help of  Store, Reducers, And Actions. 

Let’s discuss the redux change of state with an example:

Example: In this section, we are going to discuss an example of a redux change of state. The required steps are described below: Here we are going to design a react-redux app that is used to perform the to-do task. So, for that we have to perform the following steps:

Step 1: For creating the new react app we have to perform the following code in the terminal:

npx create-react-app todo

Step 2: Now, after creating and performing the above code in the terminal we have a folder named by todo. After this again go to the terminal and type:

cd todo

By this, we can say that terminal is now pointing to the todo folder files.

structure of the redux todo app

Step 3: Here we are going to create the package .json file which is mainly used for defining the dependencies that we are going to use in the project. That’s why we are creating this file.

package.json:

{
    "name": "todos",
      "version": "0.0.1",
      "private": true,
      "devDependencies": {
        "react-scripts": "^4.0.3"
      },
      "dependencies": {
        "prop-types": "^15.7.2",
           "react": "^17.0.2",
        "react-dom": "^17.0.2",
        "react-redux": "^7.2.0",
        "redux": "^4.0.5"
      },
      "scripts": {
        "start": "react-scripts start",
        "build": "react-scripts build",
        "eject": "react-scripts eject",
        "test": "react-scripts test --env=node"
      },
      "browserslist": [
        ">0.2%",
        "not dead",
        "not ie <= 11",
        "not op_mini all"
      ]
}

After defining the dependencies, we have to install them by typing the following code in the terminal:

Note: This is suggested that working on the project we use the terminal, for starting the server or the second one for installing the necessary dependencies. 

npm install

Step 4: Creating Necessary files. After all the above steps we have the following files in our todo folder:

  • node_modules
  • public
  • src
  • package-lock.json
  • package.json

Now, delete all the files present in the public and src files. So, after performing these things we are going to create the following files:

In the public folder create the file index.html. index.html the file is basically a file that is used to fetch all the data required for the app. It is the main page of the application.

index.html

HTML




<!doctype html>
<html lang="en">
  
<head>
    <meta charset="utf-8">
    <meta name="viewport" content=
          "width=device-width, initial-scale=1">
    <title>Redux Todo List</title>
</head>
  
<body>
    <div id="root"></div>
</body>
  
</html>


Now, we are going to create the following folder and files:

  • actions
  • components
  • containers
  • reducers
  • index.js

index.js file: It is the file that is used to fetch the data of all the files like a store, reducers, action, etc. Or we can say that it is the store of the react-redux application. All containers need to access it for fetching the data for further processing like updating, changing, and many more things. 

Javascript




import React from 'react'
import { render } from 'react-dom'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import App from './components/App'
import rootReducer from './reducers'
  
const store = createStore(rootReducer)
  
render(
    <Provider store={store}>
        <App />
      </Provider>,
      document.getElementById('root')
)


In the actions folder, we use the property known as “type” which is used for informing about the data that is sent to the store. We are going to create the following files:

  • index.js
  • index.spec.js

index.js file: In this file, an action is created that we are wanted to create and it also provides its id(unique number or identity). And here also define the visibility filter active of the current action.

Javascript




let nextTodoId = 0
export const addTodo = text => ({
    type: 'ADD_TODO',
    id: nextTodoId++,
    text
})
  
export const setVisibilityFilter = filter => ({
    type: 'SET_VISIBILITY_FILTER',
    filter
})
  
export const toggleTodo = id => ({
    type: 'TOGGLE_TODO',
    id
})
  
export const VisibilityFilters = {
    SHOW_ALL: 'SHOW_ALL',
    SHOW_COMPLETED: 'SHOW_COMPLETED',
    SHOW_ACTIVE: 'SHOW_ACTIVE'
}


index.spec.js:

Javascript




import * as actions from './index'
  
describe('todo actions', () => {
    it('addTodo should create ADD_TODO action', () => {
        expect(actions.addTodo('Use Redux')).toEqual({
            type: 'ADD_TODO',
            id: 0,
            text: 'Use Redux'
        })
    })
  
    it('setVisibilityFilter should create 
        SET_VISIBILITY_FILTER action', () => {
        expect(actions.setVisibilityFilter('active')).toEqual({
            type: 'SET_VISIBILITY_FILTER',
            filter: 'active'
        })
    })
  
    it('toggleTodo should create TOGGLE_TODO action', () => {
        expect(actions.toggleTodo(1)).toEqual({
            type: 'TOGGLE_TODO',
            id: 1
        })
    })
})


Step 5: After this, we are going to create the following files in the components folder:

  • App.js
  • Footer.js
  • Link.js
  • Todo.js
  • TodoList.js

The component folder is a presentation of the react-redux application which means it is the component folder we define such files which are concerned about the look of the application like style, layout, and many more. It is only used for receiving the data and rendering it via props. 

App.js file: It is the main or we can say that the root component that is received needs to be rendered on the application UI.

Javascript




import React from 'react'
import Footer from './Footer'
import AddTodo from '../containers/AddTodo'
import VisibleTodoList from '../containers/VisibleTodoList'
  
const App = () => (
    <div>
        <AddTodo />
        <VisibleTodoList />
        <Footer />
    </div>
)
  
export default App


Footer.js file: In this file or it decided where the changes should be visible in the application made by the user.

Javascript




import React from 'react'
import FilterLink from '../containers/FilterLink'
import { VisibilityFilters } from '../actions'
  
const Footer = () => (
    <div>
        <span>Show: </span>
        <FilterLink filter={VisibilityFilters.SHOW_ALL}>
            All
        </FilterLink>
        <FilterLink filter={VisibilityFilters.SHOW_ACTIVE}>
            Active
        </FilterLink>
        <FilterLink filter={VisibilityFilters.SHOW_COMPLETED}>
            Completed
        </FilterLink>
    </div>
)
  
export default Footer


Link.js file: It is used for using the callback function which is decided the action current state, for example, active, completed, etc.

Javascript




import React from 'react'
import PropTypes from 'prop-types'
  
const Link = ({ active, children, onClick }) => (
    <button
        onClick={onClick}
        disabled={active}
        style={{
            marginLeft: '4px',
        }}
    >
        {children}
    </button>
)
  
Link.propTypes = {
    active: PropTypes.bool.isRequired,
    children: PropTypes.node.isRequired,
    onClick: PropTypes.func.isRequired
}
  
export default Link


Todo.js file: It is used to represent the todo(single) item. 

Javascript




import React from 'react'
import PropTypes from 'prop-types'
  
const Todo = ({ onClick, completed, text }) => (
    <li
        onClick={onClick}
        style={{
            textDecoration: completed ? 'line-through' : 'none'
        }}
    >
        {text}
    </li>
)
  
Todo.propTypes = {
    onClick: PropTypes.func.isRequired,
    completed: PropTypes.bool.isRequired,
    text: PropTypes.string.isRequired
}
  
export default Todo


TodoList.js file: It is used to show the todos available in the current state. that is in the form of {id , text , completed}

Javascript




import React from 'react'
import PropTypes from 'prop-types'
import Todo from './Todo'
  
const TodoList = ({ todos, toggleTodo }) => (
    <ul>
        {todos.map(todo =>
            <Todo
                key={todo.id}
                {...todo}
                onClick={() => toggleTodo(todo.id)}
            />
        )}
    </ul>
)
  
TodoList.propTypes = {
    todos: PropTypes.arrayOf(PropTypes.shape({
        id: PropTypes.number.isRequired,
        completed: PropTypes.bool.isRequired,
        text: PropTypes.string.isRequired
    }).isRequired).isRequired,
    toggleTodo: PropTypes.func.isRequired
}
  
export default TodoList


Now, we are going to create the following files in the containers folder:

  • AddTodo.js
  • FilterLink.js
  • VisibleTodoList.js

In the container component, as we learned above that it is always concerned about the things working means how the data is fetching to other files or how updates are happening. It provides the data to components or we can say that layout data to the component that are rendered in the UI. It also used redux state functionality to read and dispatch the redux action for updating the data in the current UI components.

AddTodo.js file: It contains the to-do text which user wants to add to the to-do list through an ADD(Submit) button.

Javascript




import React from 'react'
import { connect } from 'react-redux'
import { addTodo } from '../actions'
  
const AddTodo = ({ dispatch }) => {
    let input
  
    return (
        <div>
            <form onSubmit={e => {
                e.preventDefault()
                if (!input.value.trim()) {
                    return
                }
                dispatch(addTodo(input.value))
                input.value = ''
            }}>
                <input ref={node => input = node} />
                <button type="submit">
                    Add Todo
                </button>
            </form>
        </div>
    )
}
  
export default connect()(AddTodo)


FilerLink.js file: It is used to set the visibility filter that needs to be set on the current state of the to-do item.

Javascript




import { connect } from 'react-redux'
import { setVisibilityFilter } from '../actions'
import Link from '../components/Link'
  
const mapStateToProps = (state, ownProps) => ({
    active: ownProps.filter === state.visibilityFilter
})
  
const mapDispatchToProps = (dispatch, ownProps) => ({
    onClick: () => dispatch(setVisibilityFilter(ownProps.filter))
})
  
export default connect(
    mapStateToProps,
    mapDispatchToProps
)(Link)


VisibleTodoList.js file: It filters the item and rendered it on the application page.

Javascript




import { connect } from 'react-redux'
import { toggleTodo } from '../actions'
import TodoList from '../components/TodoList'
import { VisibilityFilters } from '../actions'
  
const getVisibleTodos = (todos, filter) => {
    switch (filter) {
        case VisibilityFilters.SHOW_ALL:
            return todos
        case VisibilityFilters.SHOW_COMPLETED:
            return todos.filter(t => t.completed)
        case VisibilityFilters.SHOW_ACTIVE:
            return todos.filter(t => !t.completed)
        default:
            throw new Error('Unknown filter: ' + filter)
    }
}
  
const mapStateToProps = state => ({
    todos: getVisibleTodos(state.todos, state.visibilityFilter)
})
  
const mapDispatchToProps = dispatch => ({
    toggleTodo: id => dispatch(toggleTodo(id))
})
  
export default connect(
    mapStateToProps,
    mapDispatchToProps
)(TodoList)


Step 6: Now, are going to create the following files in the reducers folder:

  • index.js
  • todos.js
  • todos.spec.js
  • visibilityFilter.js

As we learn above, actions are only used to make changes in the app, and reducers it used to render that changes in the application. Hence, a reducer is a function that takes two parameters ‘Action’ and ‘State’. It reads the data sent by the action and updates it in the ‘store’ vie redux functionality.

index.js file:

Javascript




import { combineReducers } from 'redux'
import todos from './todos'
import visibilityFilter from './visibilityFilter'
  
export default combineReducers({
    todos,
      visibilityFilter
})


todos.js file:

Javascript




const todos = (state = [], action) => {
    switch (action.type) {
        case 'ADD_TODO':
            return [
                ...state,
                {
                    id: action.id,
                    text: action.text,
                    completed: false
                }
            ]
        case 'TOGGLE_TODO':
            return state.map(todo =>
                (todo.id === action.id)
                    ? { ...todo, completed: !todo.completed }
                    : todo
            )
        default:
            return state
    }
}
  
export default todos


todos.spec.js file:

Javascript




import todos from './todos'
  
describe('todos reducer', () => {
    it('should handle initial state', () => {
        expect(
            todos(undefined, {})
        ).toEqual([])
    })
  
    it('should handle ADD_TODO', () => {
        expect(
            todos([], {
                type: 'ADD_TODO',
                text: 'Run the tests',
                id: 0
            })
        ).toEqual([
            {
                text: 'Run the tests',
                completed: false,
                id: 0
            }
        ])
  
        expect(
            todos([
                {
                    text: 'Run the tests',
                    completed: false,
                    id: 0
                }
            ], {
                type: 'ADD_TODO',
                text: 'Use Redux',
                id: 1
            })
        ).toEqual([
            {
                text: 'Run the tests',
                completed: false,
                id: 0
            }, {
                text: 'Use Redux',
                completed: false,
                id: 1
            }
        ])
  
        expect(
            todos([
                {
                    text: 'Run the tests',
                    completed: false,
                    id: 0
                }, {
                    text: 'Use Redux',
                    completed: false,
                    id: 1
                }
            ], {
                type: 'ADD_TODO',
                text: 'Fix the tests',
                id: 2
            })
        ).toEqual([
            {
                text: 'Run the tests',
                completed: false,
                id: 0
            }, {
                text: 'Use Redux',
                completed: false,
                id: 1
            }, {
                text: 'Fix the tests',
                completed: false,
                id: 2
            }
        ])
    })
  
    it('should handle TOGGLE_TODO', () => {
        expect(
            todos([
                {
                    text: 'Run the tests',
                    completed: false,
                    id: 1
                }, {
                    text: 'Use Redux',
                    completed: false,
                    id: 0
                }
            ], {
                type: 'TOGGLE_TODO',
                id: 1
            })
        ).toEqual([
            {
                text: 'Run the tests',
                completed: true,
                id: 1
            }, {
                text: 'Use Redux',
                completed: false,
                id: 0
            }
        ])
    })
})


visibilityFilter.js file:

Javascript




import { VisibilityFilters } from '../actions'
  
const visibilityFilter = (state = VisibilityFilters.SHOW_ALL, action) => {
    switch (action.type) {
        case 'SET_VISIBILITY_FILTER':
            return action.filter
        default:
            return state
    }
}
  
export default visibilityFilter


Step to run the application: After performing the above steps, we completed our redux management app. To, start the app we should type in the terminal.

npm start

Output: 

OUTPUT OF THE TODO APP



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads