React Redux implementation of TodoList small case

Posted by nick1 on Fri, 14 Jan 2022 10:36:33 +0100

React Redux is a common component in react ecology, which can simplify the Redux process. (note the concepts: react, Redux and react Redux are three different things)

1. Install react Redux dependency

npm install --save react-redux

2. < provider > provider

< provider > is a provider. As long as this component is used, all other components in the component can use store, which is also the core component of react redux

import React from 'react';
import ReactDOM from 'react-dom';
import TodoList from './TodoList'
import { Provider } from 'react-redux'
import store from './store'
//Declare an App component, and then wrap the component with a Provider.
const App = (
    <Provider store={store}>
        <TodoList />
    </Provider>
)

ReactDOM.render(App, document.getElementById('root'));

3. connect connector

React Redux provides a connect method to connect mapStateToProps, mapDispatchToProps and components

1)TodoList.js component into connect

import { connect } from 'react-redux';

2) Mapping relation making

The mapping relationship is to map the original state to the props attribute in the component

mapStateToProps

const mapStateToProps = (state) => {
    return {
        inputValue : state.inputValue,
        list: state.list,
    }
}

mapDispatchToProps

const mapDispatchToProps = (dispatch) => {
    return {
        getTodoList() {
            const action = getTodoListAction();
            dispatch(action);
        },
        inputChange(e) {
            const action = changeInputAction(e.target.value);
            dispatch(action);
        },
        clickButton() {
            const action = addItemAction();
            dispatch(action);
        },
        deleteItem(index) {
            const action = deleteItemAction(index);
            dispatch(action);
        }
    }
}

Because react Redux does not support asynchronous operations, you need to introduce the middleware Redux thunk to support asynchronous operations

In the TodoList case, it is useful to obtain the List operation when the component is loaded (in the actual project, the DataSource in the List is the default result obtained from the back end. Here, a false data is simulated for convenience)

Front end Mock false data

Create a new getList folder under the public folder, and a new mock under the getList folder JSON file

 mock.json file

{
    "list":[
        "Get up at 4 a.m. and exercise",
        "Swimming after work for an hour at noon",
        "From 8 p.m. to 10 p.m., study for two hours"
    ]
}

store folder

Generally, the store folder is divided into reducer js   index.js   constants. JS (or actionTypes.js) and actioncreators js

First, to obtain data, the component will first create an action, which is an object containing the type (i.e. actionType) and value of the action, and then the store will distribute the action. After receiving the action, the store will give it to the reducer JS, where the default data and processed data are stored. After the reducer processes the data, it returns a new state to the store; Then, the component needs to obtain the new state. Generally, the function store is obtained through setstate; Set the state of the current component; this. setState(store.getState())

index.js

This introduces Redux thunk middleware

import {createStore, applyMiddleware, compose} from 'redux';
import reducer from './reducer';    //Introduction of ruducer
import thunk from 'redux-thunk';

// Using compose to create a compose enhancement function is equivalent to establishing a chain function
const composeEnhancers =   window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?
                           window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
// Enhancement function combined with thunk
const enhancer = composeEnhancers(applyMiddleware(thunk))

// Create a data warehouse
const store = createStore(reducer, enhancer)   
 
export default store;

actionTypes.js

All action s of the TodoList case are stored here

export const CHANGE_INPUT = 'changeInput';
export const ADD_ITEM = 'ADD_ITEM';
export const DELETE_ITEM = 'DELETE_ITEM';
export const GET_LIST = 'GET_LIST';

 actionCreators.js

This corresponds to all action processing methods

import { CHANGE_INPUT, ADD_ITEM, DELETE_ITEM, GET_LIST } from "./actionTypes";
import axios from 'axios';

export const changeInputAction = (value) => ({
    type: CHANGE_INPUT,
    payload: value
})

export const addItemAction = () => ({
    type: ADD_ITEM,
})

export const deleteItemAction = (index) => ({
    type: DELETE_ITEM,
    payload: index
})

export const getListAction = (data) => ({
    type: GET_LIST,
    payload: data
})

export const getTodoListAction = () =>{
    return (dispatch) => {
        axios.get('/getList/mock.json')
        .then((res) => {
            const data = res.data;
            const action = getListAction(data);
            dispatch(action);
        })
    }
}

reducer.js

This corresponds to a business processing logic of action

import { CHANGE_INPUT, ADD_ITEM, DELETE_ITEM, GET_LIST } from './actionTypes'
const defalutState = {
    inputValue : 'Write Something',
    list :[]
}

export default (state = defalutState, action) =>{
    if (action.type === CHANGE_INPUT) {
        let newState = JSON.parse(JSON.stringify(state));
        newState.inputValue = action.payload;
        return newState;
    }
    if (action.type === ADD_ITEM) {
        let newState = JSON.parse(JSON.stringify(state));
        newState.list.push(newState.inputValue);
        newState.inputValue = '';
        return newState;
    }
    if (action.type === DELETE_ITEM) {
        let newState = JSON.parse(JSON.stringify(state));
        newState.list.splice(action.payload, 1);
        return newState;
    }
    if(action.type === GET_LIST){ //Write business logic according to the type value
        let newState = JSON.parse(JSON.stringify(state)) 
        newState.list = action.payload.list //Duplicate List array
        return newState
    }
    return state
}

The class component implements the TodoList case in combination with the componentDidMount life cycle

TodoList.js

// eslint-disable-next-line
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Input, Button, List } from '../../../redux3-redux-thunk/node_modules/antd/lib';
import { getTodoListAction, changeInputAction, addItemAction, deleteItemAction } from './store/actionCreators';
import 'antd/dist/antd.css';

// class component writing
class TodoList extends Component {

    componentDidMount() {
        this.props.getTodoList()
    }

    render() {
        const { inputValue, inputChange, clickButton, list, deleteItem } = this.props;
        
        return (
            <div style={{margin: "10px"}}>
                <div>
                    <Input value={inputValue} onChange={inputChange} style={{ width:'250px', marginRight:'10px'}}/>
                    <Button type="primary" onClick={clickButton}>increase</Button>
                </div>
                <div style={{margin:'10px',width:'300px'}}>
                <List
                    bordered
                    dataSource={list}
                    renderItem={(item, index)=>(<List.Item key={index} onClick={() => deleteItem(index)}>{item}</List.Item>)}
                />
                </div>
            </div>
            );
    }
}

const mapStateToProps = (state) => {
    return {
        inputValue : state.inputValue,
        list: state.list,
    }
}

const mapDispatchToProps = (dispatch) => {
    return {
        getTodoList() {
            const action = getTodoListAction();
            dispatch(action);
        },
        inputChange(e) {
            const action = changeInputAction(e.target.value);
            dispatch(action);
        },
        clickButton() {
            const action = addItemAction();
            dispatch(action);
        },
        deleteItem(index) {
            const action = deleteItemAction(index);
            dispatch(action);
        }
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(TodoList);

Implementation of TodoList with stateless components and hooks

import React, { useEffect } from 'react';
import { connect } from 'react-redux';
import { Input, Button, List } from '../../../redux3-redux-thunk/node_modules/antd/lib';
import { getTodoListAction, changeInputAction, addItemAction, deleteItemAction } from './store/actionCreators';
import 'antd/dist/antd.css';


// Stateless component writing
const TodoList = (props) => {
   const { inputValue, inputChange, clickButton, list, deleteItem, getTodoList } = props;

     useEffect(() => {
         getTodoList()
    },[])// eslint-disable-line react-hooks/exhaustive-deps

     return (
         <div style={{margin: "10px"}}>
             <div>
                 <Input value={inputValue} onChange={inputChange} style={{ width:'250px', marginRight:'10px'}}/>
                 <Button type="primary" onClick={clickButton}>increase</Button>
            </div>
             <div style={{margin:'10px',width:'300px'}}>
                 <List
                    bordered
                    dataSource={list}
                    renderItem={(item, index)=>(<List.Item key={index} onClick={() => deleteItem(index)}>{item}</List.Item>)}
                 />   
             </div>
         </div>
     )
}

const mapStateToProps = (state) => {
    return {
        inputValue : state.inputValue,
        list: state.list,
    }
}

const mapDispatchToProps = (dispatch) => {
    return {
        getTodoList() {
            const action = getTodoListAction();
            dispatch(action);
        },
        inputChange(e) {
            const action = changeInputAction(e.target.value);
            dispatch(action);
        },
        clickButton() {
            const action = addItemAction();
            dispatch(action);
        },
        deleteItem(index) {
            const action = deleteItemAction(index);
            dispatch(action);
        }
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(TodoList);

TodoList case run:

If you want to further understand the process of react Redux, you can debug it through the Redux DevTools tool

Topics: Front-end React