1, redux understanding
1. Learning documents
- English documents: https://redux.js.org/
- Chinese documents: http://www.redux.org.cn/
- Github: https://github.com/reactjs/redux
2. What is redux
- redux is a JS library dedicated to state management (not a react plug-in library).
- It can be used in react, angular, vue and other projects, but it is basically used in conjunction with react.
- Function: centrally manage the shared state of multiple components in react application.
3. Under what circumstances do you need to use redux
- The status of a component needs to be available (shared) by other components at any time.
- One component needs to change the state (Communication) of another component.
- 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
- Action object
- 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 - Example: {type: 'ADD_STUDENT', data:{name: 'tom', age:18}}
2,reducer
- Used for initialization status and machining status.
- During processing, a pure function of a new state is generated according to the old state and action.
3, store
- An object that links state, action, and reducer
- How do I get this object?
- import {createStore} from 'redux'
- import reducer from './reducers'
- const store = createStore(reducer)
- What is the function of this object?
- getState(): get state
- dispatch(action): distribute the action, trigger the reducer call, and generate a new state
- 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> <button onClick={this.increment}>+</button> <button onClick={this.decrement}>-</button> <button onClick={this.incrementIfOdd}>The current sum is odd plus</button> <button onClick={this.incrementAsync}>Asynchronous addition</button> </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> <button onClick={this.increment}>+</button> <button onClick={this.decrement}>-</button> <button onClick={this.incrementIfOdd}>The current sum is odd plus</button> <button onClick={this.incrementAsync}>Asynchronous addition</button> </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> <button onClick={this.increment}>+</button> <button onClick={this.decrement}>-</button> <button onClick={this.incrementIfOdd}>The current sum is odd plus</button> <button onClick={this.incrementAsync}>Asynchronous addition</button> </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> <button onClick={this.increment}>+</button> <button onClick={this.decrement}>-</button> <button onClick={this.incrementIfOdd}>The current sum is odd plus</button> <button onClick={this.incrementAsync}>Asynchronous addition</button> </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
-
createstore()
Function: create a store object containing the specified reducer -
store object
1. Function: the core management object of redux Library
2. It internally maintains:
1) state
2) reducer3. 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) -
applyMiddleware()
Role: redux based Middleware (plug-in library) in application -
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
- A react plug-in library
- Designed to simplify the use of redux in react applications
2. React Redux divides all components into two categories
- UI components
- It is only responsible for UI rendering without any business logic
- Receive data through props (general data and functions)
- Do not use any Redux API s
- It is generally saved in the components folder
- Container assembly
- Responsible for managing data and business logic, not UI presentation
- Use Redux's API
- 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> <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> <button onClick={this.increment}>+</button> <button onClick={this.decrement}>-</button> <button onClick={this.incrementIfOdd}>The current sum is odd plus</button> <button onClick={this.incrementAsync}>Asynchronous addition</button> </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> <button onClick={this.increment}>+</button> <button onClick={this.decrement}>-</button> <button onClick={this.incrementIfOdd}>The current sum is odd plus</button> <button onClick={this.incrementAsync}>Asynchronous addition</button> </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> <button onClick={this.increment}>+</button> <button onClick={this.decrement}>-</button> <button onClick={this.incrementIfOdd}>The current sum is odd plus</button> <button onClick={this.incrementAsync}>Asynchronous addition</button> </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
- A special kind of function: as long as it is the same input (argument), it must get the same output (return)
- Some of the following constraints must be observed
- Parameter data must not be overwritten
- There will be no side effects, such as network requests, input and output devices
- Cannot call date Now () or math Impure methods such as random()
- 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
- Understanding: a special class of functions
1) Case 1: the parameter is a function
2) Case 2: return is a function - Common higher-order functions:
- Timer setting function
- forEach()/map()/filter()/reduce()/find()/bind() of array
- promise
- connect function in react Redux
- 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