React learning notes -- redux

Posted by mikesheridan5 on Wed, 05 Jan 2022 11:29:44 +0100

1, redux understanding

1. Learning documents

  1. English documents: https://redux.js.org/
  2. Chinese documents: http://www.redux.org.cn/
  3. Github: https://github.com/reactjs/redux

2. What is redux

  1. redux is a JS library dedicated to state management (not a react plug-in library).
  2. It can be used in react, angular, vue and other projects, but it is basically used in conjunction with react.
  3. Function: centrally manage the shared state of multiple components in react application.

3. Under what circumstances do you need to use redux

  1. The status of a component needs to be available (shared) by other components at any time.
  2. One component needs to change the state (Communication) of another component.
  3. General principle: don't use it if you can. If you don't have to work hard, consider using it.

4. redux workflow

2, Three core concepts of redux

1,action

  1. Action object
  2. Contains 2 attributes
    type: identifies the attribute. The value is a string. It is unique and necessary
    Data: data attribute, any value type, optional attribute
  3. Example: {type: 'ADD_STUDENT', data:{name: 'tom', age:18}}

2,reducer

  1. Used for initialization status and machining status.
  2. During processing, a pure function of a new state is generated according to the old state and action.

3, store

  1. An object that links state, action, and reducer
  2. How do I get this object?
  1. import {createStore} from 'redux'
  2. import reducer from './reducers'
  3. const store = createStore(reducer)
  1. What is the function of this object?
  1. getState(): get state
  2. dispatch(action): distribute the action, trigger the reducer call, and generate a new state
  3. subscribe(listener): register to listen. When a new state is generated, it will be called automatically

3, Introduce the case of Redux programming

design sketch

1. Use pure react to write

directory structure

index.jsx

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'

ReactDOM.render(<App />, document.getElementById('root'))

App.jsx

import React, { Component } from 'react'
import Count from './components/Count/Count'
export default class App extends Component {
  render () {
    return (
      <div>
        <Count />
      </div>
    )
  }
}

Count under components jsx

import React, { Component } from 'react'

export default class Count extends Component {

	state = {count:0}

	//addition
	increment = ()=>{
		const {value} = this.selectNumber
		const {count} = this.state
		this.setState({count:count+value*1})
	}
	//subtraction
	decrement = ()=>{
		const {value} = this.selectNumber
		const {count} = this.state
		this.setState({count:count-value*1})
	}
	//Odd plus
	incrementIfOdd = ()=>{
		const {value} = this.selectNumber
		const {count} = this.state
		if(count % 2 !== 0){
			this.setState({count:count+value*1})
		}
	}
	//Asynchronous addition
	incrementAsync = ()=>{
		const {value} = this.selectNumber
		const {count} = this.state
		setTimeout(()=>{
			this.setState({count:count+value*1})
		},500)
	}

	render() {
		return (
			<div>
				<h1>The current summation is:{this.state.count}</h1>
				<select ref={c => this.selectNumber = c}>
					<option value="1">1</option>
					<option value="2">2</option>
					<option value="3">3</option>
				</select>&nbsp;
				<button onClick={this.increment}>+</button>&nbsp;
				<button onClick={this.decrement}>-</button>&nbsp;
				<button onClick={this.incrementIfOdd}>The current sum is odd plus</button>&nbsp;
				<button onClick={this.incrementAsync}>Asynchronous addition</button>&nbsp;
			</div>
		)
	}
}

2. Redux Lite

directory structure

index.js

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import store from './redux/store'

ReactDOM.render(<App />, document.getElementById('root'))

store.subscribe(() => { //The purpose is to let render execute once the state changes
  ReactDOM.render(<App />, document.getElementById('root'))
})

App.jsx

import React, { Component } from 'react'
import Count from './components/Count'

export default class App extends Component {
	render() {
		return (
			<div>
				<Count/>
			</div>
		)
	}
}

Indext. Under Count under components jsx

import React, { Component } from 'react'
//store is introduced to obtain the saved status in redux
import store from '../../redux/store'

export default class Count extends Component {

	state = {carName:'Benz c63'}

	/* componentDidMount(){
		//Detect the change of state in redux, and call render whenever it changes
		store.subscribe(()=>{
			this.setState({})
		})
	} */

	//addition
	increment = ()=>{
		const {value} = this.selectNumber
		store.dispatch({type:'increment',data:value*1})
	}
	//subtraction
	decrement = ()=>{
		const {value} = this.selectNumber
		store.dispatch({type:'decrement',data:value*1})
	}
	//Odd plus
	incrementIfOdd = ()=>{
		const {value} = this.selectNumber
		const count = store.getState()
		if(count % 2 !== 0){
			store.dispatch({type:'increment',data:value*1})
		}
	}
	//Asynchronous addition
	incrementAsync = ()=>{
		const {value} = this.selectNumber
		setTimeout(()=>{
			store.dispatch({type:'increment',data:value*1})
		},500)
	}

	render() {
		return (
			<div>
				<h1>The current summation is:{store.getState()}</h1>
				<select ref={c => this.selectNumber = c}>
					<option value="1">1</option>
					<option value="2">2</option>
					<option value="3">3</option>
				</select>&nbsp;
				<button onClick={this.increment}>+</button>&nbsp;
				<button onClick={this.decrement}>-</button>&nbsp;
				<button onClick={this.incrementIfOdd}>The current sum is odd plus</button>&nbsp;
				<button onClick={this.incrementAsync}>Asynchronous addition</button>&nbsp;
			</div>
		)
	}
}

Count under redux_ reducer. js

/* 
	1.This file is used to create a reducer serving the Count component. The essence of the reducer is a function
	2.reducer The function receives two parameters: the previous state and the action object
*/

const initState = 0 //Initialization status
export default function countReducer(preState=initState,action){
	// console.log(preState);
	//Get: type, data from the action object
	const {type,data} = action
	//Determine how to process data according to type
	switch (type) {
		case 'increment': //If it's plus
			return preState + data
		case 'decrement': //If it is minus
			return preState - data
		default:
			return preState
	}
}

Store under redux js

/* 
	This file is specially used to expose a store object. The whole application has only one store object
*/

//createStore is introduced to create the most core store object in redux
import {createStore} from 'redux'
//Introduce reducer serving Count component
import countReducer from './count_reducer'
//Expose store
export default createStore(countReducer)

summary
(1). Remove the state of the Count component itself

(2). Create under SRC:
-redux
-store.js
-count_reducer.js

(3).store.js:
1). The createStore function in redux is introduced to create a store
2). When createstore is called, a reducer serving it should be passed in
3). Remember to expose the store object

(4).count_reducer.js:
1). The essence of reducer is a function that receives: preState,action, and returns the processed state
2).reducer has two functions: initialization status and machining status
3). When the reducer is called for the first time, it is automatically triggered by the store,
The passed preState is undefined,
The action passed is: {type: '@ @ reduce / init_a.2. B.4}

(5). In index JS to monitor the state changes in the store, and re render < app / >
Note: redux is only responsible for managing the status. As for the change of status driving the display of the page, we have to write it ourselves.

3. Full Redux


index.js

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import store from './redux/store'

ReactDOM.render(<App/>,document.getElementById('root'))

store.subscribe(()=>{
	ReactDOM.render(<App/>,document.getElementById('root'))
})

App.jsx

import React, { Component } from 'react'
import Count from './components/Count'

export default class App extends Component {
	render() {
		return (
			<div>
				<Count/>
			</div>
		)
	}
}

Index under Count under components jsx

import React, { Component } from 'react'
//store is introduced to obtain the saved status in redux
import store from '../../redux/store'
//actionCreator is introduced to create action objects
import {createIncrementAction,createDecrementAction} from '../../redux/count_action'

export default class Count extends Component {

	state = {carName:'Benz c63'}

	/* componentDidMount(){
		//Detect the change of state in redux, and call render whenever it changes
		store.subscribe(()=>{
			this.setState({})
		})
	} */

	//addition
	increment = ()=>{
		const {value} = this.selectNumber
		store.dispatch(createIncrementAction(value*1))
	}
	//subtraction
	decrement = ()=>{
		const {value} = this.selectNumber
		store.dispatch(createDecrementAction(value*1))
	}
	//Odd plus
	incrementIfOdd = ()=>{
		const {value} = this.selectNumber
		const count = store.getState()
		if(count % 2 !== 0){
			store.dispatch(createIncrementAction(value*1))
		}
	}
	//Asynchronous addition
	incrementAsync = ()=>{
		const {value} = this.selectNumber
		setTimeout(()=>{
			store.dispatch(createIncrementAction(value*1))
		},500)
	}

	render() {
		return (
			<div>
				<h1>The current summation is:{store.getState()}</h1>
				<select ref={c => this.selectNumber = c}>
					<option value="1">1</option>
					<option value="2">2</option>
					<option value="3">3</option>
				</select>&nbsp;
				<button onClick={this.increment}>+</button>&nbsp;
				<button onClick={this.decrement}>-</button>&nbsp;
				<button onClick={this.incrementIfOdd}>The current sum is odd plus</button>&nbsp;
				<button onClick={this.incrementAsync}>Asynchronous addition</button>&nbsp;
			</div>
		)
	}
}

Constant under redux js

/* 
	This module is used to define the constant value of type in the action object. It has only one purpose: to facilitate management and prevent programmers from writing wrong words
*/
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'

Count under redux_ action. js

/* 
	This file is dedicated to generating action objects for the Count component
*/
import {INCREMENT,DECREMENT} from './constant'

export const createIncrementAction = data => ({type:INCREMENT,data})
export const createDecrementAction = data => ({type:DECREMENT,data})

Count under redux_ reducer. js

/* 
	1.This file is used to create a reducer serving the Count component. The essence of the reducer is a function
	2.reducer The function receives two parameters: the previous state and the action object
*/
import {INCREMENT,DECREMENT} from './constant'

const initState = 0 //Initialization status
export default function countReducer(preState=initState,action){
	// console.log(preState);
	//Get: type, data from the action object
	const {type,data} = action
	//Determine how to process data according to type
	switch (type) {
		case INCREMENT: //If it's plus
			return preState + data
		case DECREMENT: //If it is minus
			return preState - data
		default:
			return preState
	}
}

Store under redux js

/* 
	This file is specially used to expose a store object. The whole application has only one store object
*/

//createStore is introduced to create the most core store object in redux
import {createStore} from 'redux'
//Introduce reducer serving Count component
import countReducer from './count_reducer'
//Expose store
export default createStore(countReducer)

summary
New file:
1.count_action.js is specifically used to create action objects
2.constant.js places easily misspelled type values

4. Asynchronous Action version

Or the example above
Changed documents
Index under Count under components jsx

import React, { Component } from 'react'
//store is introduced to obtain the saved status in redux
import store from '../../redux/store'
//actionCreator is introduced to create action objects
import {
	createIncrementAction,
	createDecrementAction,
	createIncrementAsyncAction
} from '../../redux/count_action'

export default class Count extends Component {

	state = {carName:'Benz c63'}

	/* componentDidMount(){
		//Detect the change of state in redux, and call render whenever it changes
		store.subscribe(()=>{
			this.setState({})
		})
	} */

	//addition
	increment = ()=>{
		const {value} = this.selectNumber
		store.dispatch(createIncrementAction(value*1))
	}
	//subtraction
	decrement = ()=>{
		const {value} = this.selectNumber
		store.dispatch(createDecrementAction(value*1))
	}
	//Odd plus
	incrementIfOdd = ()=>{
		const {value} = this.selectNumber
		const count = store.getState()
		if(count % 2 !== 0){
			store.dispatch(createIncrementAction(value*1))
		}
	}
	//Asynchronous addition
	incrementAsync = ()=>{
		const {value} = this.selectNumber
		// setTimeout(()=>{
			store.dispatch(createIncrementAsyncAction(value*1,500))
		// },500)
	}

	render() {
		return (
			<div>
				<h1>The current summation is:{store.getState()}</h1>
				<select ref={c => this.selectNumber = c}>
					<option value="1">1</option>
					<option value="2">2</option>
					<option value="3">3</option>
				</select>&nbsp;
				<button onClick={this.increment}>+</button>&nbsp;
				<button onClick={this.decrement}>-</button>&nbsp;
				<button onClick={this.incrementIfOdd}>The current sum is odd plus</button>&nbsp;
				<button onClick={this.incrementAsync}>Asynchronous addition</button>&nbsp;
			</div>
		)
	}
}

Count under Redux_ actions. js

/* 
	This file is dedicated to generating action objects for the Count component
*/
import {INCREMENT,DECREMENT} from './constant'

//Synchronous action means that the value of action is a general Object of type Object
export const createIncrementAction = data => ({type:INCREMENT,data})
export const createDecrementAction = data => ({type:DECREMENT,data})

//Asynchronous action means that the value of action is a function. Synchronous action is generally called in asynchronous action. Asynchronous action is not necessary.
export const createIncrementAsyncAction = (data,time) => {
	return (dispatch)=>{
		setTimeout(()=>{
			dispatch(createIncrementAction(data))
		},time)
	}
}

Store under Redux js

/* 
	This file is specially used to expose a store object. The whole application has only one store object
*/

//createStore is introduced to create the most core store object in redux
import { createStore, applyMiddleware } from 'redux'
//Introduce reducer serving Count component
import countReducer from './count_reducer'
//Redux thunk is introduced to support asynchronous action s
import thunk from 'redux-thunk'
//Expose store
export default createStore(countReducer, applyMiddleware(thunk))

Everything else is exactly the same as above
summary
(1). Clear: the delayed action does not want to be handed over to the component itself, but to the action

(2). When asynchronous action is needed: you want to operate on the status, but the specific data is returned by the asynchronous task.

(3). Specific code:
1). Yarn add Redux thunk and configure it in the store
2). The function that creates an action no longer returns a general object, but a function that writes asynchronous tasks.
3). After the asynchronous task has a result, a synchronous action is distributed to actually operate the data.

(4). Note: asynchronous actions do not have to be written. You can wait for the results of asynchronous tasks before distributing synchronous actions.

4, Summary of core API of redux

  1. createstore()
    Function: create a store object containing the specified reducer

  2. store object

    1. Function: the core management object of redux Library

    2. It internally maintains:
    1) state
    2) reducer

    3. Core approach:
    1) getState()
    2) dispatch(action)
    3) subscribe(listener)

    4. Specific coding
    1) store.getState()
    2) store.dispatch({type:'INCREMENT', number})
    3) store.subscribe(render)

  3. applyMiddleware()
    Role: redux based Middleware (plug-in library) in application

  4. combineReducers()
    Function: merge multiple reducer functions

5, Basic use of reacr Redux (the official plug-in library is not the same thing as redux. Redux is a third party)

1. Understand

  1. A react plug-in library
  2. Designed to simplify the use of redux in react applications

2. React Redux divides all components into two categories

  1. UI components
    1. It is only responsible for UI rendering without any business logic
    2. Receive data through props (general data and functions)
    3. Do not use any Redux API s
    4. It is generally saved in the components folder
  2. Container assembly
    1. Responsible for managing data and business logic, not UI presentation
    2. Use Redux's API
    3. It is generally saved in the containers folder

3. Connecting container components to UI components

In the above example, containers \ count \ count. Is added jsx

containers\Count\Count.jsx

//UI component of Count
import CountUI from '../../components/Count/Count'
//Connect is introduced to connect UI components with redux
import { connect } from 'react-redux'

//Use connect()() to create and expose a container component of Count
export default connect()(CountUI)

components\Count\Count.jsx

import React, { Component } from 'react'

export default class Count extends Component {

  increment = () => {
    const { value } = this.selectNumber
  }

  decrement = () => {
    const { value } = this.selectNumber
  }

  incrementIfOdd = () => {
    const { value } = this.selectNumber
  }

  incrementAsync = () => {
    const { value } = this.selectNumber
  }


  render () {
    return (
      <div>
        <h1>Current summation is: ???</h1>
        <select ref={c => this.selectNumber = c}>
          <option value="1">1</option>
          <option value="2">2</option>
          <option value="3">3</option>
        </select>&nbsp;
        <button onClick={this.increment}>plus</button>
        <button onClick={this.decrement}>reduce</button>
        <button onClick={this.incrementIfOdd}> The current sum is odd plus</button>
        <button onClick={this.incrementAsync}>Asynchronous addition</button>
      </div>
    )
  }
}

App.jsx

import React, { Component } from 'react'
import Count from './containers/Count/Count'
import store from './Redux/store'
export default class App extends Component {
  render () {
    return (
      <div>
        {/* Pass store to container component */}
        <Count store={store} />
      </div>
    )
  }
}

The others are the same as those above

4. Basic use of react Redux

Or the above example, and make modifications based on the above example
containers\Count\Count.jsx

//UI component of Count
import CountUI from '../../components/Count'
//Introduce action
import {
	createIncrementAction,
	createDecrementAction,
	createIncrementAsyncAction
} from '../../redux/count_action'

//Connect is introduced to connect UI components with redux
import {connect} from 'react-redux'

/* 
	1.mapStateToProps Function returns an object;
	2.The key in the returned object is the key passed to the UI component props, and the value is the value passed to the UI component props
	3.mapStateToProps Used to transfer status
*/
function mapStateToProps(state){
	return {count:state}
}

/* 
	1.mapDispatchToProps Function returns an object;
	2.The key in the returned object is the key passed to the UI component props, and the value is the value passed to the UI component props
	3.mapDispatchToProps Method for transferring operation status
*/
function mapDispatchToProps(dispatch){
	return {
		jia:number => dispatch(createIncrementAction(number)),
		jian:number => dispatch(createDecrementAction(number)),
		jiaAsync:(number,time) => dispatch(createIncrementAsyncAction(number,time)),
	}
}

//Use connect()() to create and expose a container component of Count
export default connect(mapStateToProps,mapDispatchToProps)(CountUI)


components\Count\Count.jsx

import React, { Component } from 'react'

export default class Count extends Component {


	//addition
	increment = ()=>{
		const {value} = this.selectNumber
		this.props.jia(value*1)
	}
	//subtraction
	decrement = ()=>{
		const {value} = this.selectNumber
		this.props.jian(value*1)
	}
	//Odd plus
	incrementIfOdd = ()=>{
		const {value} = this.selectNumber
		if(this.props.count % 2 !== 0){
			this.props.jia(value*1)
		}
	}
	//Asynchronous addition
	incrementAsync = ()=>{
		const {value} = this.selectNumber
		this.props.jiaAsync(value*1,500)
	}

	render() {
		//console. Log ('props received by UI component is', this.props);
		return (
			<div>
				<h1>The current summation is:{this.props.count}</h1>
				<select ref={c => this.selectNumber = c}>
					<option value="1">1</option>
					<option value="2">2</option>
					<option value="3">3</option>
				</select>&nbsp;
				<button onClick={this.increment}>+</button>&nbsp;
				<button onClick={this.decrement}>-</button>&nbsp;
				<button onClick={this.incrementIfOdd}>The current sum is odd plus</button>&nbsp;
				<button onClick={this.incrementAsync}>Asynchronous addition</button>&nbsp;
			</div>
		)
	}
}


The others are the same as those above
summary
(1). Define two concepts:
1).UI component: you can't use any redux api, only responsible for page rendering, interaction, etc.
2). Container component: responsible for communicating with redux and delivering the results to the UI component.
(2). How to create a container component -- rely on the connect function of react Redux
connect(mapStateToProps,mapDispatchToProps)(UI component)
-mapStateToProps: mapping state. The return value is an object
-mapDispatchToProps: method for mapping operation status. The return value is an object
(3). Note 1: the store in the container component is passed in by props, not directly introduced in the container component
(4). Note 2: mapDispatchToProps can also be an object

5. The above example code is optimized

On the basis of the above example, there are some places that can be optimized
(1). Container components and UI components integrate into one file

(2). You don't need to pass the store to the container component, just wrap a < provider store = {store} > for < app / >.

(3). After using react Redux, there is no need to detect the change of state in redux. The container component can complete this work automatically.

(4).mapDispatchToProps can also be simply written as an object

(5). How many steps does a component have to go through to "deal with redux"?
1). Defined UI components - not exposed
2). Introduce connect to generate a container component and expose it. The writing method is as follows:
connect(
State = > ({key: value}), / / mapping status
{key: xxxaction} / / method for mapping operation status
)(UI component)

(3). In the UI component, use this props. XXXXXXXX read and operation status

Optimized directory structure

index.jsx

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import store from './redux/store'
import {Provider} from 'react-redux'

ReactDOM.render(
	<Provider store={store}>
		<App/>
	</Provider>,
	document.getElementById('root')
)

App.jsx

import React, { Component } from 'react'
import Count from './containers/Count'

export default class App extends Component {
	render() {
		return (
			<div>
				<Count/>
			</div>
		)
	}
}

Constant under redux js

/* 
	This module is used to define the constant value of type in the action object. It has only one purpose: to facilitate management and prevent programmers from writing wrong words
*/
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'

Count under redux_ action. js

/* 
	This file is dedicated to generating action objects for the Count component
*/
import {INCREMENT,DECREMENT} from './constant'

//Synchronous action means that the value of action is a general Object of type Object
export const createIncrementAction = data => ({type:INCREMENT,data})
export const createDecrementAction = data => ({type:DECREMENT,data})

//Asynchronous action means that the value of action is a function. Synchronous action is generally called in asynchronous action. Asynchronous action is not necessary.
export const createIncrementAsyncAction = (data,time) => {
	return (dispatch)=>{
		setTimeout(()=>{
			dispatch(createIncrementAction(data))
		},time)
	}
}

Count under redux_ reducer. js

/* 
	1.This file is used to create a reducer serving the Count component. The essence of the reducer is a function
	2.reducer The function receives two parameters: the previous state and the action object
*/
import {INCREMENT,DECREMENT} from './constant'

const initState = 0 //Initialization status
export default function countReducer(preState=initState,action){
	// console.log(preState);
	//Get: type, data from the action object
	const {type,data} = action
	//Determine how to process data according to type
	switch (type) {
		case INCREMENT: //If it's plus
			return preState + data
		case DECREMENT: //If it is minus
			return preState - data
		default:
			return preState
	}
}

Store under redux js
Main optimization areas

/* 
	This file is specially used to expose a store object. The whole application has only one store object
*/

//createStore is introduced to create the most core store object in redux
import {createStore,applyMiddleware} from 'redux'
//Introduce reducer serving Count component
import countReducer from './count_reducer'
//Redux thunk is introduced to support asynchronous action s
import thunk from 'redux-thunk'
//Expose store
export default createStore(countReducer,applyMiddleware(thunk))

Index. Under Count under contractors jsx

import React, { Component } from 'react'
//Introduce action
import {
	createIncrementAction,
	createDecrementAction,
	createIncrementAsyncAction
} from '../../redux/count_action'
//Connect is introduced to connect UI components with redux
import {connect} from 'react-redux'

//Define UI components
class Count extends Component {

	state = {carName:'Benz c63'}

	//addition
	increment = ()=>{
		const {value} = this.selectNumber
		this.props.jia(value*1)
	}
	//subtraction
	decrement = ()=>{
		const {value} = this.selectNumber
		this.props.jian(value*1)
	}
	//Odd plus
	incrementIfOdd = ()=>{
		const {value} = this.selectNumber
		if(this.props.count % 2 !== 0){
			this.props.jia(value*1)
		}
	}
	//Asynchronous addition
	incrementAsync = ()=>{
		const {value} = this.selectNumber
		this.props.jiaAsync(value*1,500)
	}

	render() {
		//console. Log ('props received by UI component is', this.props);
		return (
			<div>
				<h1>The current summation is:{this.props.count}</h1>
				<select ref={c => this.selectNumber = c}>
					<option value="1">1</option>
					<option value="2">2</option>
					<option value="3">3</option>
				</select>&nbsp;
				<button onClick={this.increment}>+</button>&nbsp;
				<button onClick={this.decrement}>-</button>&nbsp;
				<button onClick={this.incrementIfOdd}>The current sum is odd plus</button>&nbsp;
				<button onClick={this.incrementAsync}>Asynchronous addition</button>&nbsp;
			</div>
		)
	}
}

//Use connect()() to create and expose a container component of Count
export default connect(
	state => ({count:state}),

	//General writing of mapDispatchToProps
	/* dispatch => ({
		jia:number => dispatch(createIncrementAction(number)),
		jian:number => dispatch(createDecrementAction(number)),
		jiaAsync:(number,time) => dispatch(createIncrementAsyncAction(number,time)),
	}) */

	//Short for mapDispatchToProps
	{
		jia:createIncrementAction,
		jian:createDecrementAction,
		jiaAsync:createIncrementAsyncAction,
	}
)(Count)


6. The above example implements data sharing

On the basis of the above example, a group of person related components and redux related files are added
The directory structure is

index.jsx

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import store from './redux/store'
import {Provider} from 'react-redux'

ReactDOM.render(
	/* Here, you need to wrap the App with a Provider so that all descendant container components of the App can receive the store */
	<Provider store={store}>
		<App/>
	</Provider>,
	document.getElementById('root')
)

App.jsx

import React, { Component } from 'react'
import Count from './containers/Count' //Container component of introduced Count
import Person from './containers/Person' //Container component of introduced Person

export default class App extends Component {
	render() {
		return (
			<div>
				<Count/>
				<hr/>
				<Person/>
			</div>
		)
	}
}

Index under Count under containers jsx

import React, { Component } from 'react'
//Introduce action
import {
	increment,
	decrement,
	incrementAsync
} from '../../redux/actions/count'
//Connect is introduced to connect UI components with redux
import {connect} from 'react-redux'

//Define UI components
class Count extends Component {

	state = {carName:'Benz c63'}

	//addition
	increment = ()=>{
		const {value} = this.selectNumber
		this.props.increment(value*1)
	}
	//subtraction
	decrement = ()=>{
		const {value} = this.selectNumber
		this.props.decrement(value*1)
	}
	//Odd plus
	incrementIfOdd = ()=>{
		const {value} = this.selectNumber
		if(this.props.count % 2 !== 0){
			this.props.increment(value*1)
		}
	}
	//Asynchronous addition
	incrementAsync = ()=>{
		const {value} = this.selectNumber
		this.props.incrementAsync(value*1,500)
	}

	render() {
		//console. Log ('props received by UI component is', this.props);
		return (
			<div>
				<h2>I am Count assembly,The total number of people in the lower assembly is:{this.props.renshu}</h2>
				<h4>The current summation is:{this.props.count}</h4>
				<select ref={c => this.selectNumber = c}>
					<option value="1">1</option>
					<option value="2">2</option>
					<option value="3">3</option>
				</select>&nbsp;
				<button onClick={this.increment}>+</button>&nbsp;
				<button onClick={this.decrement}>-</button>&nbsp;
				<button onClick={this.incrementIfOdd}>The current sum is odd plus</button>&nbsp;
				<button onClick={this.incrementAsync}>Asynchronous addition</button>&nbsp;
			</div>
		)
	}
}

//Use connect()() to create and expose a container component of Count
export default connect(
	state => ({
		count:state.count,
		personCount:state.persons.length
	}),
	{increment,decrement,incrementAsync}
)(Count)


Index under Person under containers jsx

import React, { Component } from 'react'
import {nanoid} from 'nanoid'
import {connect} from 'react-redux'
import {addPerson} from '../../redux/actions/person'

class Person extends Component {

	addPerson = ()=>{
		const name = this.nameNode.value
		const age = this.ageNode.value*1
		const personObj = {id:nanoid(),name,age}
		this.props.addPerson(personObj)
		this.nameNode.value = ''
		this.ageNode.value = ''
	}

	render() {
		return (
			<div>
				<h2>I am Person assembly,The sum of the upper components is{this.props.count}</h2>
				<input ref={c=>this.nameNode = c} type="text" placeholder="Enter name"/>
				<input ref={c=>this.ageNode = c} type="text" placeholder="Enter age"/>
				<button onClick={this.addPerson}>add to</button>
				<ul>
					{
						this.props.persons.map((p)=>{
							return <li key={p.id}>{p.name}--{p.age}</li>
						})
					}
				</ul>
			</div>
		)
	}
}

export default connect(
	state => ({
		persons:state.persons,
		count:state.count
	}),//Mapping state
	{addPerson}//Method of mapping operation state
)(Person)

Count under actions under redux js

/* 
	This file is dedicated to generating action objects for the Count component
*/
import {INCREMENT,DECREMENT} from '../constant'

//Synchronous action means that the value of action is a general Object of type Object
export const increment = data => ({type:INCREMENT,data})
export const decrement = data => ({type:DECREMENT,data})

//Asynchronous action means that the value of action is a function. Synchronous action is generally called in asynchronous action. Asynchronous action is not necessary.
export const incrementAsync = (data,time) => {
	return (dispatch)=>{
		setTimeout(()=>{
			dispatch(increment(data))
		},time)
	}
}

Person under actions under redux js

import {ADD_PERSON} from '../constant'

//Create an action object to add a person
export const addPerson = personObj => ({type:ADD_PERSON,data:personObj})

Count under reducers under redux js

/* 
	1.This file is used to create a reducer serving the Count component. The essence of the reducer is a function
	2.reducer The function receives two parameters: the previous state and the action object
*/
import {INCREMENT,DECREMENT} from '../constant'

const initState = 0 //Initialization status
export default function countReducer(preState=initState,action){
	// console.log('countReducer@#@#@#');
	//Get: type, data from the action object
	const {type,data} = action
	//Determine how to process data according to type
	switch (type) {
		case INCREMENT: //If it's plus
			return preState + data
		case DECREMENT: //If it is minus
			return preState - data
		default:
			return preState
	}
}

Person under reducers under redux js

import {ADD_PERSON} from '../constant'

//Initializes the list of people
const initState = [{id:'001',name:'tom',age:18}]

export default function personReducer(preState=initState,action){
	// console.log('personReducer@#@#@#');
	const {type,data} = action
	switch (type) {
		case ADD_PERSON: //If you add a person
			//preState.unshift(data) / / you can't write this here. This will cause the prestate to be rewritten, and the personReducer is not a pure function.
			return [data,...preState]
		default:
			return preState
	}
}

Index under reducers under redux js

/* 
	This file is used to summarize all reducers into a total reducer
*/
//combineReducers is introduced to summarize multiple reducers
import {combineReducers} from 'redux'
//Introduce reducer serving Count component
import count from './count'
//Introduce a reducer that serves the Person component
import persons from './person'

//Summarize all reducers to become a total reducer
export default  combineReducers({
	count,
	persons
})

Constant under redux js

/* 
	This module is used to define the constant value of type in the action object. It has only one purpose: to facilitate management and prevent programmers from writing wrong words
*/
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
export const ADD_PERSON = 'add_person'

Store under redux js

/* 
	This file is specially used to expose a store object. The whole application has only one store object
*/

//createStore is introduced to create the most core store object in redux
import {createStore,applyMiddleware} from 'redux'
//reducer after introducing summary
import reducer from './reducers'
//Redux thunk is introduced to support asynchronous action s
import thunk from 'redux-thunk'
//Introducing Redux devtools extension
import {composeWithDevTools} from 'redux-devtools-extension'

//Expose store 
export default createStore(reducer,composeWithDevTools(applyMiddleware(thunk)))

Final effect

Summary:
(1). Define a Pserson component and share data with the Count component through redux.
(2). Write: reducer and action for the Person component, and configure the constant constant constant.
(3). Important: the Person reducer and the Count reducer should be merged by using combineReducers. The total state after merging is one object!!!
(4). The store is handed over to the general reducer. Finally, when taking out the status in the component, remember to "take it in place".
(5). All variable names shall be standardized, and the short form of trigger object shall be used as much as possible.
(6). In the reducers folder, write index JS is specifically used to summarize and expose all reducers

6, Pure function and higher order function

1. Pure function

  1. A special kind of function: as long as it is the same input (argument), it must get the same output (return)
  2. Some of the following constraints must be observed
    1. Parameter data must not be overwritten
    2. There will be no side effects, such as network requests, input and output devices
    3. Cannot call date Now () or math Impure methods such as random()
  3. The reducer function of redux must be a pure function

For example, in the above example, the person under reducers JS can't be written like this. It's not a pure function

import { ADDPERSON } from '../constant'
import { nanoid } from 'nanoid'
const initState = [{ id: nanoid(), name: 'tom', age: 18 }]
export default function personReducer (preState = initState, action) {
  const { type, data } = action
  switch (type) {
    // case ADDPERSON:
    //   preState.unshift(data)
    //   return preState
    //The above description is not a pure function, because the parameter preState is rewritten, and the personReducer is not a pure function
    case ADDPERSON:
      return [data, ...preState]
    default:
      return preState
  }

}

2. Higher order function

  1. Understanding: a special class of functions
    1) Case 1: the parameter is a function
    2) Case 2: return is a function
  2. Common higher-order functions:
    1. Timer setting function
    2. forEach()/map()/filter()/reduce()/find()/bind() of array
    3. promise
    4. connect function in react Redux
  3. Function: it can realize more dynamic and scalable functions

7, Using redux debugging tool

1. First download the tool from the chrome store

2. In the project (a library needs to be imported for normal use), execute the following command
npm install --save-dev redux-devtools-extension
3. Modify store js

Topics: Javascript Front-end React