Open In App

What Is Redux Change of State ?

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:

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:

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:

CHANGE OF STATE

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

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:

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




<!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:

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. 




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 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.




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:




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:

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.




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.




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.




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. 




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}




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:

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.




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.




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.




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:

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:




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

todos.js file:




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:




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:




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


Article Tags :