One. What is redux

Redux is a predictable state container for JavaScript apps. Redux is a predictable state container for JS applications.

Why redux?

Without Redux, if two components (not parent-child relationships) need to communicate, multiple intermediate components may be required to message for them, wasting resources and making the code complex.

In Redux, a single data source Store is proposed to Store state data. All components can modify the Store through Action or obtain the latest state from the Store. Redux is the perfect way to communicate between components

How to use Redux?

Redux official image

React Component: People who borrow books

Action Creator: Loudspeaker (for notifying librarians)

-Leonard: The Store

Reducer: Small volume (The librarian has a poor memory and needs to record the book information in a small volume

The ReactComponent said a word (Action Creator) and borrowed a book from the library manager (Store). However, the library manager was too old to remember, so he took out his own Reducers. I looked at it and found out if it was there, where it was, how it was. In this way the librarian takes the book and gives it to the borrower.

Translation:

When the component wants to obtain State, it creates a request with ActionCreator and sends it to the Store. The Store confirms the State with the Reducer. The Reducer returns a result to the Store, which then passes the State to the component.

4. Learn Redux through TodoList

Install the story:

NPM install redux --save # or yarn add reduxCopy the code

The project catalog is shown below

SRC /index.js entry file

import React from "react";
import ReactDOM from "react-dom";
import App from "./TodoList";
ReactDOM.render(<App></App>, document.getElementById("root"));
Copy the code

src/TodoList.js

import React, { Component } from "react"; import "antd/dist/antd.css"; import { Input, Button, List } from "antd"; import store from "./store"; import { changeValue, addListItem, removeListItem, getList, } from "./store/actionCreators"; class App extends Component { constructor(props) { super(props); this.state = store.getState(); store.subscribe(() => this.storeChange()); } storeChange() { this.setState(store.getState()); } componentDidMount() { const action = getList(); store.dispatch(action); } render() { return ( <div style={{ margin: "10px" }}> <div> <Input placeholder={this.state.inputValue} style={{ width: "250px", marginRight: OnChange ={(e) => this.changevalue (e)} /> <Button type="primary" onClick={() => this.addListitem ()}> Add </Button> </div> <div style={{ margin: "10px", width: "300px" }}> <List bordered dataSource={this.state.list} renderItem={(item, index) => ( <List.Item onClick={(item) => this.removeListItem(item, index)}> {item} </List.Item> )} /> </div> </div> ); } changeValue(e) { const action = changeValue(e.target.value); store.dispatch(action); } addListItem() { const action = addListItem(); store.dispatch(action); } removeListItem(item, index) { const action = removeListItem(index); store.dispatch(action); } } export default App;Copy the code

SRC /store/index.js redux entry file

import { createStore, applyMiddleware, compose } from "redux";
import reducer from "./reducer";
import thunk from "redux-thunk";
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
  ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({})
  : compose;

const enhancer = composeEnhancers(applyMiddleware(thunk));
const store = createStore(reducer, enhancer);
export default store;
Copy the code

SRC/store/actionCreators action

import {
  CHANGE_VALUE,
  ADD_LIST_ITEM,
  REMOVE_LIST_ITEM,
  GET_ACTION,
} from "./actionTypes";
import axios from "axios";
export const changeValue = (value) => {
  return {
    type: CHANGE_VALUE,
    value,
  };
};
export const addListItem = (value) => {
  return {
    type: ADD_LIST_ITEM,
    value,
  };
};
export const removeListItem = (value) => {
  return {
    type: REMOVE_LIST_ITEM,
    value,
  };
};
export const getAction = (data) => {
  return {
    type: GET_ACTION,
    value: data,
  };
};
export const getList = () => {
  return (dispatch) => {
    axios
      .get(
        "https://www.fastmock.site/mock/6f4fec629859811f980f52a147ea3236/xbb_pl/xbb"
      )
      .then((res) => {
        const data = res.data;
        const action = getAction(data);
        dispatch(action);
      });
  };
};
Copy the code

The SRC /store/actionTypes variables store files

export const CHANGE_VALUE = "changeValue";
export const ADD_LIST_ITEM = "addListItem";
export const REMOVE_LIST_ITEM = "removeListItem";
export const GET_ACTION = "getAction";
Copy the code

src/store/reducer.js

import { ADD_LIST_ITEM, REMOVE_LIST_ITEM, CHANGE_VALUE, GET_ACTION, } from "./actionTypes"; const defaultState = { inputValue: "Write Something", list: [" Morning meeting at 8am to assign today's development work ", "Development requirements meeting with project manager at 9am "," Today's code review at 5:30 PM ",],}; export default (state = defaultState, action) => { if (action.type === CHANGE_VALUE) { const newState = JSON.parse(JSON.stringify(state)); newState.inputValue = action.value; return newState; } if (action.type === ADD_LIST_ITEM) { console.log(state); let newState = JSON.parse(JSON.stringify(state)); newState.list.push(newState.inputValue); //push new content to the list return newState; } if (action.type === REMOVE_LIST_ITEM) { let newState = JSON.parse(JSON.stringify(state)); newState.list.splice(action.value, 1); //push new content to the list return newState; } if (action.type === GET_ACTION) { let newState = JSON.parse(JSON.stringify(state)); newState.list = action.value.list; return newState; } return state; };Copy the code

5. Potholes encountered when using Redux

Stores must be unique

Stores must be unique. Multiple stores are never allowed. Only one store is allowed

Only the Store can change its content, but the Reducer cannot

Reudcer only returned the changed data, but did not change the data in the store. The store got the data from the Reducer and updated itself.

Reducer must be a pure function

If the function is called with the same arguments, the same result is always returned. It does not depend on any changes in state or data outside the function during program execution and must depend only on its input parameters.

6. Tips for redux’s actual development

Extract Action Types as constants

When writing Redux Action, we write a lot of Action distributions, resulting in a lot of Action Types. If we need to name the Action by ourselves, there will be two basic problems:

  • If these Types are not managed uniformly, it is not conducive to the use of large projects, and the Settings will generate redundant codes.
  • Because the Type in the Action must correspond to the Type in the Reducer one by one, there is no clear error in the browser after this part of code or letter is written wrong, which brings great difficulty to debugging.

I’ll split the Action Type into a separate file. In the SRC /store folder, create a new actiontypes.js file and manage the Type set in the file.

export const  CHANGE_INPUT = 'changeInput'
export const  ADD_ITEM = 'addItem'
export const  DELETE_ITEM = 'deleteItem'
Copy the code

benefits

1. Redundant code can be avoided

2. If we write the wrong constant name, the program will directly report the error in the browser and console, which can speed up the development efficiency and reduce the time to find the error.

Manage all Redux actions in one file

Redux middleware redux-Thunk

Redux-thunk Is the most commonly used plug-in for Redux. When will this plugin be used? For example, after dispatching an Action and before arriving at the reducer, additional operations need to be done using middleware. In practice you can use middleware to log, create crash reports, invoke asynchronous interfaces, or route. This middleware can be enhanced with Redux-Thunk (you can use other middleware as well), which is an enhancement of Redux dispatch,

1. Install redux-Thunk

npm install --save redux-thunk
Copy the code

2. Configure redux-thunk

Introduce applyMiddleware. If you want to use middleware, you must introduce applyMiddleware in Redux

import { createStore , applyMiddleware } from 'redux'
Copy the code

Introduction of story – thunk library

import thunk from 'redux-thunk'
Copy the code

Recommended Official Documents

Const store = createStore(Reducer, applyMiddleware(thunk)) // Create a data storeCopy the code

The final configuration

However, we can no longer use the redux-DevTools plug-in, so we should configure it this way using enhancements

import { createStore , applyMiddleware ,compose } from 'redux' import reducer from './reducer' import thunk from 'redux-thunk' const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}):compose const enhancer = composeEnhancers(applyMiddleware(thunk)) const Store = createStore(reducer, enhancer) // Create a data storage repository export default store // Expose itCopy the code

Use of redux-thunk

Before the redux-Thunk middleware was introduced, we could only request data in the TodeList class components. With redux-Thunk, we could do something about the actions when the Store passed state into the reducer.

Write the business logic in actionActionine.js

Actionactionine.js used to be defined actions, so you couldn’t write the business logic. With Redux-Thunk, you can write the componentDidMount business logic in Todolist.js. That is, the code that requests data from the background is put in the actionActioncreans.js file. So we need to introduce Axios and write a new function method. (Once actions were objects, now actions can be functions. That’s what redux-thunk brings.)

import axios from 'axios' ... something... export const getTodoList = () =>{ return ()=>{ axios.get('https://www.easy-mock.com/mock/5cfcce489dc7c36bd6da2c99/xiaojiejie/getList').then((res)=>{ const data = res.data console.log(data) }) } }Copy the code

Now we need to execute the method and view the results on the console, where we can modify the componentDidMount code in the todolist.js file.

GetTodoList import {getTodoList, changeInputAction, addItemAction ,deleteItemAction,getListAction} from './store/actionCreatores' ---something--- componentDidMount(){ const  action = getTodoList() store.dispatch(action) }Copy the code

Then we go to the browser console and check to see if we’ve got the data that was sent to us from the back end. If everything works, we should. Once we get that, we can just continue with the old Redux process.

export const getTodoList = () =>{
    return (dispatch)=>{
        axios.get('https://www.easy-mock.com/mock/5cfcce489dc7c36bd6da2c99/xiaojiejie/getList').then((res)=>{
            const data = res.data
            const action = getListAction(data)
            dispatch(action)

        })
    }
}
Copy the code