react-redux of redux and react-redux study notes



foreword

At work, Vue is the mainstay, and the use of React is getting rusty, and I can only use redux to the point of being able to use it. Occasionally, I come across a React project. Using redux means rewriting what others have written. Recently, I had time to visit the React tutorial for free at Bilibili . Write a note and record it! ! !


1. What are redux and react-redux?

Redux is a JavaScript state container that provides predictable state management. It is an independent library that can be used with UI frameworks.
Slightly different from redux, react-redux is React's official Redux UI binding library. The process of subscribing to store, checking for updated data and triggering re-rendering can become more general and reusable.
To put it simply, react-redux still uses redux to fetch data in the end, but it encapsulates an api that is convenient for using redux.
Compared with the simple brainless operation of Vuex, these two are a little troublesome. However, Alibaba later encapsulated a hox, which feels much easier to use.

2. Redux usage steps

1. Import library

The code is as follows (example):

npm install react-redux

2. Schematic

insert image description here

Schematic Interpretation

1.所有的UI组件都应该包裹一个容器组件,他们是父子关系
2.容器组件是真正和redux打交道的,里面可以随意的使用redux的api
3.UI组件不能使用任何redux的api
4.容器组件会传给UI组件:1)redux中所保存的状态,2)用于操作状态的方法
5.备注:容器给UI传递:状态、操作状态的方法,均通过props传递

actions

1) Meaning

Actions are payloads that pass data from the application to the store. It is the only source of store data. Generally you pass the action to the store via store.dispatch().

action返回的是Object类型的叫做同步action
action返回的是Function类型的叫做异步 action
异步action:
(1).明确:延迟的动作不想交给组件自身,想交给action
(2).何时需要异步action:想要对状态进行操作,但是具体的数据靠异步任务返回(非必须)
(3).具体编码:
    1).cnpm i redux-thunk,并配置在store中,//行驶转换程序
    2).创建action的函数不再返回一般对象,而是一个函数,该函数中写异步任务
    3).异步任务有结果后,分发一个同步的action去真正的操作数据
(4).备注:异步action不是必须要写的,完全可以自己等待异步任务的结果再去分发同步action

2)demo

//redux文件夹下新建constant.js文件
/* 该模块适用于定义action对象中type类型的常量值
目的只有一个:便于管理的同时防止单词写错   
 */

export const INCREMENT = 'increment'

export const DECREMENT = 'decrement'

export const SET_OPERATOR = 'setOperator'
//redux文件夹下新建action文件夹
//action下新建count_actions.js
/*
 该文件专门为Count组件生成求和count_actions对象   
 */

import {
    
    INCREMENT, DECREMENT} from '../constant'

export const incrementAction = (data) => ({
    
     type: INCREMENT, data })//同步action
//同步action,就是指action的返回值为Object类型的一般对象
export function decrementAction(data){
    
       
    return {
    
         
        type: DECREMENT, 
        data   
    }//返回的是一个对象,普通数据类型,同步action,返回对象为异步
}
//异步action,就是指action的返回值为函数
//异步action中,一般都会调用同步action,异步action不是必须要用的
export const incrementAsyncAction = (data, time) => {
    
    
    return (dispatch)=>{
    
    //返回对象为异步action
        setTimeout(()=>{
    
    
            dispatch(incrementAction(data))
        }, time)
    }
}
//action下新建user_action.js
import {
    
     SET_OPERATOR } from '../constant'

export function setOperator(data){
    
    
    return{
    
    
        type: SET_OPERATOR,
        data,
    } 
}

store.js

1) Meaning

store is a state manager, a warehouse that stores public state data. Redux apps have a single store

1)引入redux中的createStore函数,创建一个store
2)createStore调用时要传入一个为其服务的reducer
3)记得暴露store对象
4)  redux只负责管理状态,至于状态的改变驱动着页面的展示要靠我们自己写

2)demo

//redux文件夹新建store.js
//引入creacteStore,专门用于创建redux中最核心的store对象,applyMiddleware执行中间件
import {
    
     legacy_createStore as createStore, applyMiddleware} from "redux";
//引入redux-thunk用于支持异步action
import thunk from 'redux-thunk'
//引入为组件服务的reducer
import rootReducers   from './reducers'
const store  = createStore(rootReducers, applyMiddleware(thunk))
//暴露出去
export default store

reducer.js

1) Meaning

Reducers specify how changes in the application state are sent to the store in response to actions. Remember that actions only describe the fact that something happened, not how the application updates the state.

1)reducer的本质是一个函数,接收:preState,action,发布加工后的状态
2)reducer有两个作用:初始状态,加工状态
3)reducer被第一次调用时,是store自动触发的,传递的preState是undefined

2)demo

//redux文件夹下新建reducers文件夹
//新建count_reducer.js
import {
    
    INCREMENT, DECREMENT} from '../constant'
//监测提交过来的action,preState是前一条数据,初始化时默认为0
const counter = (preState = 0,action)=>{
    
    
    const {
    
    type, data}= action
    switch(type){
    
    
        case INCREMENT:
            return preState + data;
        case DECREMENT:
            return preState - data;
        default:
            return preState;
    }
}

export default counter;
//redux文件夹下新建reducers文件夹
//新建user_reducer.js
import {
    
     SET_OPERATOR } from '../constant'

const operator = (preState = {
     
     }, action)=>{
    
    
    const {
    
    type, data}= action
    switch(type){
    
    
        case SET_OPERATOR:
            return Object.assign(preState, data);
        default :
            return preState
    }
}

export default operator;
//redux文件夹下新建reducers文件夹
//新建index.js

import {
    
     combineReducers } from 'redux';
import counter from './count_reducer';
import operator from './user_reducer'

// 合并多个 reduce
const rootReducers = combineReducers({
    
    
    counter:counter,
    operator:operator
});

export default rootReducers;

Count.jsx

1) Meaning

Operation component, which contains two functions of data addition and subtraction, and data assignment

2)demo

//引入Count的UI组件
// import CountUI from '../../components/Count'
//引入action  
import {
    
     
    incrementAction, 
    decrementAction, 
    incrementAsyncAction 
} from '../../redux/actions/count_actions'
//引入connect用于连接UI组件与redux
import {
    
     connect } from 'react-redux'
// import store from '../../redux/store'
import React, {
    
     Component } from 'react'
import store from '../../redux/store'

import {
    
     setOperatorAction } from '../../redux/actions/user_action'

class Count extends Component {
    
    
    state = {
    
    
        
    }
    
    //加
    increment=()=>{
    
    
        const {
    
    value}=this.selectNumber
        this.props.increment(value*1)
    }
    //减
    decrement=()=>{
    
    
        const {
    
     value } = this.selectNumber
        this.props.decrement(value*1)
    }
    //当前求和的数据为奇数再加
    incrementIfOdd=()=>{
    
    
        const counter = this.props.count.counter
        const {
    
     value } = this.selectNumber
        if(counter % 2 !=0) {
    
    
            this.props.increment(value*1)
        }
        
    }
    //异步加
    incrementAsync=()=>{
    
    
        const {
    
     value } = this.selectNumber
        this.props.incrementAsync(value*1, 1000)
    }
    addUserInfo = () => {
    
    
        const operator = {
    
    
            name: '大黄'+Math.floor(Math.random()*100),
            age: Math.floor(Math.random()*100)
        }
        this.props.setOperator(operator)
    }   
    render() {
    
    
        console.log(this.props)
        return (
            <div> 
                <h2>Person数组的长度{
    
    this.props.personLen.length}</h2>
                <h1>当前求和为{
    
    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()}}>如果为奇数</button>
                <button onClick={
    
    ()=>{
    
    this.incrementAsync ()}}>异步增加 </button>
            </div>
        )
    }
}
//a函数的返回对象的key就作为传递给UI组件props的key,value就作为传递给UI组props的value---状态
const mapStateToProps = (state)=> ({
    
    count: state.counter, personLen: state.operator})
//b函数的返回对象的key就作为传递给UI组件props的key,value就作为传递给UI组props的value---操作状态的方法
//一般写法 
// const mapDispatchToProps = (dispatch)=> ({
    
    
//     increment: (number)=> dispatch(incrementAction(number)),
//     decrement: (number)=> dispatch(decrementAction(number)),
//     incrementAsync: (number)=> dispatch(incrementAsyncAction(number, 2000)),
// })
//高级写法
//因为用了react-redux能够自动dispatch
const mapDispatchToProps = {
    
    
    increment: incrementAction,
    decrement: decrementAction,
    incrementAsync: incrementAsyncAction,
    setOperator: setOperatorAction
}
//创建一个容器组件
const CountContainer = connect(mapStateToProps, mapDispatchToProps)(Count)
//暴露容器组件
export default CountContainer;

//export default connect()(CountUI)
  
//App.js
import Count from './container/Count'
import Person from './container/Person'
// import store from './redux/store'
function App() {
    
    
  return (
    <div className="App">
      <Count/>
      <hr/>
      <Person/>
    </div>
  );
}

export default App;


1)明确两个概念:
    1UI组件:不能使用redux的api,只负责页面的呈现和交互等
    2)容器组件:负责和redux通信,将结果交给UI组件
2)如何创建一个容器组件---react-redux的connect函数
    connect(mapStateToProps, mapDispatchToProps)(UI组件)
    -mapStateToProps:映射状态,返回值是一个对象
    -mapDispatchToProps:映射操作状态的方法,返回值是一个对象
3)备注:容器组件中的store是靠props穿进去的,而不是在容器组件中直接引入

Person.jsx

//引入Count的UI组件
// import CountUI from '../../components/Count'
//引入action  
//引入connect用于连接UI组件与redux
import {
    
     connect } from 'react-redux'
// import store from '../../redux/store'
import React, {
    
     Component } from 'react'
import {
    
     setOperatorAction } from '../../redux/actions/user_action'

class Count extends Component {
    
    
    state = {
    
    
        
    }
    addUserInfo = () => {
    
    
        const name = this.nameNode.value
        const age = this.ageNode.value
        const personObj = {
    
    id: Math.floor(Math.random()*100), name, age}
        this.props.setOperator(personObj)
        this.nameNode.value = ''
        this.ageNode.value = ''
        console.log(name, age)
    }   
    render() {
    
    
        console.log(this.props.operator, this.props.count)
        return (
            <div> 
                <h2>Person组件,Count组件的总和为{
    
    this.props.count}</h2>
                <div>
                    <input ref={
    
    c=> this.nameNode= c} type="text" placeholder="输入名字"/>
                    <input ref={
    
    c=> this.ageNode= c} type="text"  placeholder="输入年龄"/>
                    <button onClick={
    
    ()=>{
    
    this.addUserInfo()}}>添加用户信息</button>
                    <ul>
                        {
    
    
                            this.props.operator.map(item=>{
    
    
                                return <li key={
    
    item.id}>{
    
    item.name}---{
    
    item.age}</li>
                            })
                        }
                    </ul>
                </div>
            </div>
        )
    }
}
//a函数的返回对象的key就作为传递给UI组件props的key,value就作为传递给UI组props的value---状态
const mapStateToProps = (state)=> ({
    
    operator: state.operator, count: state.counter})
//高级写法
//因为用了react-redux能够自动dispatch
const mapDispatchToProps = {
    
    
    setOperator: setOperatorAction
}
//创建一个容器组件
const CountContainer = connect(mapStateToProps, mapDispatchToProps)(Count)
//暴露容器组件
export default CountContainer;

//export default connect()(CountUI)
  
1)定义一个Person组件,和Count组件通过redux共享数据
2)为Person组件编写,reducer、action,配置constant常量
3)重点:Person的reducer和Count的Reducer要使用combineReducer进行合并,合并后的总状态是一个对象
4)交给store的是总reducer,最后注意在组件中取出状态的时候,记得取到位
//index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import store from './redux/store'
import App from './App';
import {
    
    Provider} from 'react-redux'

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
   /*给容器组件传递store */
  <Provider store={
    
    store}>
    <App />
  </Provider>
);  
// 监听redux中状态的变化,如果redux的状态发生了变化,
//那么重新渲染App组件
//react-redux不用再监测了
// store.subscribe(() => {
    
    
//   root.render(
//     <Provider store={store}>
//       <App />
//     </Provider>
//   );  
// })

3. Use of redux developer tools

npm i redux-devtools-extension
store文件
//引入redux-devtools-extension
import {
    
     composeWithDevTools } from 'redux-devtools-extension'

// const store  = createStore(rootReducers, composeWithDevTools())
const store  = createStore(rootReducers, composeWithDevTools(applyMiddleware(thunk)))

Summarize

1)容器组件和UI组件整合成一个文件
2)无需自己给容器组件传递store,给<App/>包裹 <Provider store={
    
    store}>即可
3)使用了react-redux无需自己检测redux中状态的变化,容器组件可以自动完成这个工作
4)mapDispatchToProps也可以简写成一个对象
5)一个组件要和redux打交道要经过几步?
    1)定义好UI组件---不暴露
    2)引入connect生成一个容器组件,并暴露,写法如下:
        connect(state=>(
            {
    
    key:value},//映射状态
        ),
        {
    
    
            key:action//映射操作状态的方法
        })UI组件中通过this.props.***读取和操作状态

Guess you like

Origin blog.csdn.net/chenacxz/article/details/127837231