React系统学习笔记--超基础--超详细--超简洁--Redux(七)

PartⅦ:Redux

1 redux理解

学习文档

英文文档:https://redux.js.org/

中文文档:http://www.redux.org.cn/

Github:https://github.com/reactjs/redux

redux是什么

redux是一个专门用于做状态管理的JS库(不是react插件库)

它可以用在react,angular,vue等项目中,但基本与react配合使用

作用:集中式管理react应用中多个组件共享的状态

什么情况下需要使用redux

某个组件的状态,需要让其他组件可以随时拿到(共享)

一个组件需要改变另一个组件的状态(通信)

总体原则:能不用就不用, 如果不用比较吃力才考虑使用

redux工作流程

redux 工作流程图

2 redux的三个核心概念

action

  1. 动作的对象

  2. 包含2个属性

    type:标识属性, 值为字符串, 唯一, 必要属性

    data:数据属性, 值类型任意, 可选属性

  3. 例子:{ type: ‘ADD_STUDENT’,data:{name: ‘tom’,age:18} }

reducer

  1. 用于初始化状态、加工状态,初始化时传入的previousState是undefined
  2. 加工时,根据旧的state和action, 产生新的state的纯函数(以下为纯函数概念)
  • 纯函数:一类特别的函数: 只要是同样的输入(实参),必定得到同样的输出(返回)
  • 必须遵守以下一些约束
    1. 不得改写参数数据
    2. 不会产生任何副作用,例如网络请求,输入和输出设备
    3. 不能调用Date.now()或者Math.random()等不纯的方法
  1. redux的reducer函数必须是一个纯函数

store

  1. 将state、action、reducer联系在一起的对象

  2. 如何得到此对象?

    • import {createStore} from ‘redux’
    • import reducer from ‘./reducers’
    • const store = createStore(reducer)
  3. 此对象的功能?

    • getState(): 得到state

    • dispatch(action): 分发action, 触发red ucer调用, 产生新的state

    • subscribe(listener): 注册监听, 当产生了新的state时, 自动调用

3 redux的核心API

createstore()与applyMiddleware()

createstore()作用:创建包含指定reducer的store对象,目前已被弃用(2022.11)

applyMiddleware()作用:应用上基于redux的中间件(插件库)

store对象

作用: redux库最核心的管理对象

它内部维护着:

  • state

  • reducer

核心方法:

  • getState()

  • dispatch(action)

  • subscribe(listener)

具体编码:

  • store.getState()

  • store.dispatch({type:‘INCREMENT’, number})

  • store.subscribe(render)

combineReducers()

作用:合并多个reducer函数

//代码示例
------------------ redux/reducers/index.js ------------------------------------
/**
 * 该文件用于汇总所有的reducer为一个总的reducer
 */
//引入combineReducers,用于汇总多个reducer
import {
    
    combineReducers} from 'redux'
//引入为Count组件服务的reducer
import count from './count'
import persons from './person'

//汇总所有的reducer变为一个总的reducer
export default combineReducers({
    
    
  count,persons
})

4 redux基础求和案例

redux精简版案例

src下准备好redux文件夹,文件下有store.jsreducer.js

store.js

//新写法,创建redux最为核心的store对象
import {
    
     legacy_createStore as createStore } from 'redux'
//引入为Count组件服务的reducer
import countReducer from './count_reducer'

export default createStore(countReducer)

reducer.js

//初始化状态---注意现在状态不放在组件里
const initState = 99
export default function countReducer(preState = initState, action) {
    
    
    //从action对象中获取:type,data
    const {
    
     type, data } = action
    //根据type决定如何加工数据
    switch (type) {
    
    
        case 'increment':
            return preState + data
        case 'decrement':
            return preState - data
        default:
            return preState
    }

}

Count.jsx组件

//获取redux中的状态getState
<h1>当前求和为:{
    
    store.getState()}</h1>

//引入store
import store from '../../redux/store'

//允许组件还有自己的状态
state = {
    
     car: '保时捷' }

//redux更新完状态需要重新渲染,这样写不是最佳方案,因为如果组件多的话每个都要写
//可以在入口文件中引入store,将App挂载的时候包裹在store.subscribe里面,状态一变化,App组件都将重新渲染
componentDidMount() {
    
    
    //监测redux中状态的变化,只要变化,就调用render
    store.subscribe(() => {
    
    
        this.setState({
    
    })
    })
}

increment = () => {
    
    
    const {
    
     value } = this.selectNumber
    store.dispatch({
    
     type: 'increment', data: value * 1 })
}
decrement = () => {
    
    
    const {
    
     value } = this.selectNumber
    store.dispatch({
    
     type: 'decrement', data: value * 1 })
}

入口文件index.js

// 状态改变重新渲染 App 组件
store.subscribe(() => {
    
    
  ReactDOM.render(<App />, document.getElementById('root'))
})

备注:redux只负责管理状态,状态改变驱动页面显示需要我们自己来

redux完整版案例

多了两个文件constant.jsaction.js

constant.js

//该模块用于定义action对象中type类型的常量值,以防单词写错
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'

action.js

//该文件专门为Count组件生成action对象
import {
    
     INCREMENT, DECREMENT } from "./constant"

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

Count.js组件

//不用自己写action对象,直接调用
increment = () => {
    
    
    const {
    
     value } = this.selectNumber
    store.dispatch(createIncrementAction(value * 1))
}
decrement = () => {
    
    
    const {
    
     value } = this.selectNumber
    store.dispatch(createDecrementAction(value * 1))
}

异步action的redux版本–不在Count组件中设置定时

action有两种形式:{}同步,function异步

store默认不允许action给的值不是一般对象(简单来说就是store最终接收的必须是一个合法的包含type和data的一般对象),给函数会报错滴,这时需要一个中间件来解决redux-thunk

npm i redux-thunk

store.js

//redux中的执行中间件函数applyMiddleware
import {
    
     legacy_createStore as createStore, applyMiddleware } from 'redux'
//引入为Count组件服务的reducer
import countReducer from './count_reducer'
//引入redux-thunk中间件,用来支持异步action
import thunk from 'redux-thunk'
//暴露store,第二个参数是执行异步的中间件
export default createStore(countReducer, applyMiddleware(thunk))

有了中间件store才会帮你调异步action的函数,异步action中一般都会调用同步action

action.js

import {
    
     INCREMENT, DECREMENT } from "./constant"
import store from "./store"
//同步action,action的值是object一般对象
export const createIncrementAction = data => ({
    
     type: INCREMENT, data })
export const createDecrementAction = data => ({
    
     type: DECREMENT, data })
//异步action,action的值是函数--因为函数可以开启异步任务
export const createIncrementAsyncAction = (data, time) => {
    
    
    return () => {
    
    
        setTimeout(() => {
    
    
            store.dispatch(createIncrementAction(data))
        }, time)
    }
}

//其实还可以这样写,因为是store来调这异步函数,所以不用引入store
//因为store帮我们调的异步函数,所以知道等下要用到dispatch,store帮你传过来了
import {
    
     INCREMENT, DECREMENT } from "./constant"
//同步action,action的值是object一般对象
export const createIncrementAction = data => ({
    
     type: INCREMENT, data })
export const createDecrementAction = data => ({
    
     type: DECREMENT, data })
//异步action,action的值是函数--因为函数可以开启异步任务
export const createIncrementAsyncAction = (data, time) => {
    
    
    return (dispatch) => {
    
    
        setTimeout(() => {
    
    
            dispatch(createIncrementAction(data))
        }, time)
    }
}

Count.js组件

incrementAsync = () => {
    
    
    const {
    
     value } = this.selectNumber
    // setTimeout(() => {
    
    
    store.dispatch(createIncrementAsyncAction(value * 1, 500))
    // }, 500)
}

5 react-redux

在这里插入图片描述

理解

一个react插件库

专门用来简化react应用中使用redux

react-Redux将所有组件分成两大类

UI组件

只负责 UI 的呈现,不带有任何业务逻辑

通过props接收数据(一般数据和函数)

不使用任何 Redux 的 API

一般保存在components文件夹下,也可以直接写在容器组件中直接加工成容器组件

容器组件

负责管理数据和业务逻辑,不负责UI的呈现

使用 Redux 的 API

一般保存在ontainers文件夹下

容器组件需要实现很多功能,需要借助东西去生成

注意:store不是在容器组件中直接引入,而是在App组件中通过props传过来的

UI组件是看不见任何redux的AIPI

求和案例react-redux

首先准备好UI组件(一般放在src下的components)和容器组件(一般放在src下的containers)

容器组件Count下的index.js,注意store不在这里引入

//引入Count的UI组件
import CountUI from "../../components/CountUI";
//引入action
import {
    
     
    createIncrementAction, 
    createDecrementAction, 
    createIncrementAsyncAction } 
from "../../redux/count_action";
//引入connect用于链接UI组件和redux
import {
    
     connect } from 'react-redux'
/* mapStateToProps函数返回的是一个对象
对象中的key就作为传递给UI组件props的key,value就作为传递给UI组件props的value---容器组件把从redux中获取的状态传给UI组件
mapStateToProps用于传递状态
注意这边不需要亲自引入store,react-redux调用mapStateToProps函数时帮我们传入state了
 */
function mapStateToProps(state) {
    
    
    return {
    
     count: state }
}
/* mapDispatchToProps函数返回的是一个对象
对象中的key就作为传递给UI组件props的key,value就作为传递给UI组件props的value
mapDispatchToProps用于传递操作状态的方法
 */
function mapDispatchToProps(dispatch) {
    
    
    return {
    
    
        jia: (number) => {
    
    
            //通知redux执行加法
            dispatch(createIncrementAction(number))
        },
        jian: (number) => {
    
    
            //通知redux执行减法
            dispatch(createDecrementAction(number))
        },
        jiaAsync: (number, time) => {
    
    
            dispatch(createIncrementAsyncAction(number, time))
        }
    }
}

//创建Count容器组件
const CountContainer = connect(mapStateToProps, mapDispatchToProps)(CountUI)

export default CountContainer

UI组件

//从props中读取
<h1>当前求和为:{
    
    this.props.count}</h1>

//UI组件中不会有任何redux的API
    increment = () => {
    
    
        const {
    
     value } = this.selectNumber
        this.props.jia(value * 1)
    }
    decrement = () => {
    
    
        const {
    
     value } = this.selectNumber
        this.props.jian(value * 1)

    }
    incrementIfOdd = () => {
    
    
        const {
    
     value } = this.selectNumber
        if (this.props.count % 2 !== 0) {
    
    
            this.props.jia(value * 1)
        }
    }
    incrementAsync = () => {
    
    
        const {
    
     value } = this.selectNumber
        this.props.jiaAsync(value * 1, 500)
    }

App.js

import store from './redux/store'
//把store传递给容器组件
<Count store={
    
    store} />

优化一:mapDispatchToProps简写

//创建Count容器组件---第二个函数可以写为对象,react-redux会帮我们自动分发dispatch
export default connect(
    state => ({
    
     count: state }),
    {
    
    
        jia: createIncrementAction,
        jian: createDecrementAction,
        jiaAsync: createIncrementAsyncAction
    }
)(CountUI)

优化二:Provider组件使用

使用了react-redux之后可以不写监测redux中状态变化的代码,因为connect创建容器组件的时候就有了监测redux状态变化的能力

所以之前为什么不是自己创建容器组件,因为connect创建的可以实现自动监测redux中状态的变化

//入口文件index.js---可以不用写了
store.subscribe(() => {
    
    
  root.render(<App />)
})

如果容器组件太多,我们需要在App.jsx中一个一个去传store,太繁琐,有没有什么方法可以优化

在入口文件中用Provider组件,可以只写一次,用到store的容器组件都会被提供store

//入口文件index.js
import {
    
     Provider } from 'react-redux';

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

优化三:整合UI组件和容器组件

一个文件可以定义n个组件

定义了UI组件之后直接定义容器组件并使用,最终暴露容器组件

知识点小结

connect()()

作用: 用于包装 UI 组件生成容器组件

使用connect(mapDispatchToProps,mapDispatchToProps)(UI组件)

注意点:

  • 该方法默认传入statedispatch
  • 可以省略dispatch直接传入action方法,该api会自动帮你调用dispatch

mapStateToProps

作用:将外部的数据(即state对象)转换为UI组件的标签属性

mapStateToProps函数返回的是一个对象;

返回的对象中的key就作为传递给UI组件props的key,value就作为传递给UI组件props的value

mapStateToProps用于传递状态

mapDispatchToProps

作用:将分发action的函数转换为UI组件的标签属性

mapDispatchToProps函数返回的是一个对象;

返回的对象中的key就作为传递给UI组件props的key,value就作为传递给UI组件props的value

mapDispatchToProps用于传递操作状态的方法

可以省略dispatch,直接传入action,api将会自动调用dispatch

数据共享—重点combineReducers

多个组件的数据都放在redux中,redux用对象来存储,需要借助redux提供的combineReducers先进行合并,合并之后的总状态是一个对象

容器组件在reduxc中取状态,交给子组件UI展示

现在有Person和Count组件,进行数据共享

为Person组件创建constant、action、reducer

export const ADD_PERSON = 'add_person'
import {
    
     ADD_PERSON } from '../constant'

//创建增加一个人的action动作对象
export const createAddPersonAction = personObj => ({
    
     type: ADD_PERSON, data: personObj })
//对人状态的初始化以及加工
//引入常量
import {
    
     ADD_PERSON } from '../constant'
//初始化状态
const initState = [{
    
     id: '001', name: 'tome', age: 18 }]
//加工状态
export default function personReducer(preState = initState, action) {
    
    
    const {
    
     type, data } = action
    switch (type) {
    
    
        case ADD_PERSON:
            return [data, ...preState]
        default:
            return preState
    }
}

需要在store.js中进行合并combineReducers

//新写法,创建redux最为核心的store对象
import {
    
     legacy_createStore as createStore, applyMiddleware, combineReducers } from 'redux'
//引入为Count组件服务的reducer
import countReducer from './reducers/count'
//引入为Person服务的reducer
import personReducer from './reducers/person'
//引入redux-thunk中间件,用来支持异步action
import thunk from 'redux-thunk'

//借助personReducer汇总所有reducer
const allReducer = combineReducers({
    
    
    //谁以后可以初始化和加工这个he
    he: countReducer,
    rens: personReducer
})

//暴露store
export default createStore(allReducer, applyMiddleware(thunk))

Person组件—connect创建容器链接UI组件和redux

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

class Person extends Component {
    
    
    addPerson = () => {
    
    
        //获取用户输入
        const name = this.nameNode.value
        const age = this.ageNode.value
        const personObj = {
    
     id: nanoid(), name, age }
        this.props.jiaRen(personObj)
        this.nameNode.value = ''
        this.ageNode.value = ''
    }
    render() {
    
    
        return (
            <div>
                <h2>我是Person组件</h2>
                <input ref={
    
    c => this.nameNode = c} type="text" placeholder='输入名字' />
                <input ref={
    
    c => this.ageNode = c} type="text" placeholder='输入年龄' />
                <button onClick={
    
    this.addPerson}>添加</button>
                <ul>
                    {
    
    
                        this.props.yiduiren.map((p) => {
    
    
                            return <li key={
    
    p.id}>名字{
    
    p.name}--年龄{
    
    p.age}</li>
                        })
                    }
                </ul>
            </div>
        )
    }
}

export default connect(
    //state就是redux帮我们保存的总状态
    state => ({
    
     yiduiren: state.rens }),
    {
    
    
        jiaRen: createAddPersonAction
    }

)(Person)

同样的App.js中需要引入Person组件并展示

<Count />
<Person />

纯函数

reducer中如果preState是一个数组,不可以用push、unshift等方法进行修改,如此修改并不会修改其引用,所以diff并不会判定其发生改变,导致页面无法自动重新渲染

//浅比较,redux不认为是新数组--而且这样子写reducer就不是一个纯函数了--这边就是改写了参数preState的数据
preState.unshift(data)
return preState
//返回新数组可以
return [data, ...preState]

纯函数定义:只要是同样的输入(实参),必定得到同样的输出(返回)

遵守以下一些约束:

  • 不得改写传入的参数数据
  • 不会产生如何副作用,例如网络请求,输入输出设备
  • 不能调用Date.now()或者Math.random()等不纯的方法

redux的reducer函数必须是一个纯函数

6 使用redux调试工具

安装chrome浏览器插件

Redux DecTools

下载工具依赖包

npm i redux-devtools-extension

修改store.js

import {composeWithDevTools} from 'redux-devtools-extension'

/**
* 该文件撰文用于暴露一个store对象,整个应用只有一个store对象
*/
//引入createStore,专门用于创建redux中最为核心的store对象
import {
    
    createStore,applyMiddleware} from 'redux'
//引入汇总后的reducer
import reducer from './reducers'
//引入redux-thunk,用于支持异步action
import thunk from 'redux-thunk'
//引入redux-devtools-extension
import {
    
    composeWithDevTools} from 'redux-devtools-extension'
//暴露store
export default createStore(reducer,composeWithDevTools(applyMiddleware(thunk)))

7 求和案例的最终代码

src文件目录

src

containers

​ --Count

​ --index.jsx

​ --Person

​ --index.jsx

redux

​ --actions

​ --count.js

​ --person.js

​ --reducers

​ --count.js

​ --index.js

​ --person.js

​ --constant.js

​ --store.js

App.jsx

index.js

index.js

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包裹App,目的是让App所有的后代容器组件都能接收到store */
	<Provider store={
    
    store}>
		<App/>
	</Provider>,
	document.getElementById('root')
)

App.jsx

import React, {
    
     Component } from 'react'
import Count from './containers/Count' //引入的Count的容器组件
import Person from './containers/Person' //引入的Person的容器组件

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

redux文件

  1. action文件夹
--------------------------------count.js------------------------------------------
/**
* 该文件专门未Count组件生成对象
*/
import {
    
    INCREMENT,DECREMENT} from '../constant'

//声明同步action,就是指action的值为Object类型的一般对象
export const increment=data=>({
    
    type:INCREMENT,data})
export const decrement=data=>({
    
    type:DECREMENT,data})


//声明异步action,就是指action的值为函数,异步action中一般都会调用同步action
//在外部调用该action方法时需要引入redux-thunk,用于支持异步action
//该方法会自动传入dispatch
 export const incrementAsync=(data,time)=>{
    
    
   return (dispatch)=>{
    
    
     setTimeout(()=>{
    
    
       dispatch(increment(data))
     },time)
   }
 }
--------------------------------------person.js-------------------------------
import {
    
    ADD_PERSON} from '../constant'
//创建增加一个人的action动作对象
export const addPerson=personObj=>({
    
    
 type:ADD_PERSON,
 data:personObj
})
  1. reducers文件夹
--------------------------------count.js------------------------------------------
/**
* 1. 该文件时用于创建一个为Count组件服务的reducer.reducer的本质就是一个函数
* 2. reducer函数会接到两个参数,分别为:之前状态(preState),动作对象(action)
*/
import {
    
    
 INCREMENT,
 DECREMENT
} from '../constant'
const initState = 0 //初始化状态
export default function countReducer(preState = initState, action) {
    
    
 //从action对象中获取:type:data
 const {
    
    
   type,
   data
 } = action
 //根据type决定如何加工数据
 switch (type) {
    
    
   case INCREMENT:
     return preState + data
   case DECREMENT:
     return preState - data
   default:
     return preState
 }
}
--------------------------------------person.js-------------------------------
import {
    
    ADD_PERSON} from '../constant'
//初始化人的列表
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: //若是添加一个人
			//preState.unshift(data) //此处不可以这样写,这样会导致preState被改写了,personReducer就不是纯函数了。
			return [data,...preState]
		default:
			return preState
	}
}
--------------------------------------index.js-------------------------------
/**
* 该文件用于汇总所有的reducer为一个总的reducer
*/
//引入combineReducers,用于汇总多个reducer
import {
    
    combineReducers} from 'redux'
//引入为Count组件服务的reducer
import count from './count'
import persons from './person'

//汇总所有的reducer变为一个总的reducer
export default combineReducers({
    
    
 count,persons
})
  1. store.js
/**
* 该文件撰文用于暴露一个store对象,整个应用只有一个store对象
*/
//引入createStore,专门用于创建redux中最为核心的store对象
import {
    
    createStore,applyMiddleware} from 'redux'
//引入汇总后的reducer
import reducer from './reducers'
//引入redux-thunk,用于支持异步action
import thunk from 'redux-thunk'
//引入redux-devtools-extension
import {
    
    composeWithDevTools} from 'redux-devtools-extension'
//暴露store
export default createStore(reducer,composeWithDevTools(applyMiddleware(thunk)))

4.constant.js

/**
* 该模块是用于定义action对象中的type类型的常量值,目的只有一个:
*  便于管理的同事防止程序员单词写错
*/
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
export const ADD_PERSON = 'add_person'

containers

  1. Count文件夹的index.jsx
  import React, {
    
     Component } from 'react'

  //引入action
  import {
    
    
    increment,
    decrement,
    incrementAsync
  } from "../../redux/actions/count"
  //引入connect用于链接UI组件与redux
  import {
    
     connect } from 'react-redux'

  //定义UI组件,这个将再connect()()中加工成容器组件,就可以调用到其传入的redux状态与actions
  class Count extends Component {
    
    
    increment = () => {
    
    
      //获取出入内容
      const {
    
     value } = this.selectNumber
      this.props.increment(value * 1)
    }
    //减法
    decrement = () => {
    
    
      const {
    
     value } = this.selectNumber
      this.props.decrement(value * 1)
    }
    //奇数再加
    incrementIfOdd = () => {
    
    
      const {
    
     value } = this.selectNumber
      if (this.props.count % 2 !== 0) {
    
    
        this.props.increment(value * 1)
      }
    }
    //异步加
    incrementAsync = () => {
    
    
      const {
    
     value } = this.selectNumber
      this.props.incrementAsync(value * 1, 500)
    }

    render() {
    
    
      return (
        <div>
          <h2>我是Count组件,下方组件总人数为:{
    
    this.props.personCount}</h2>
          <h4>当前求和为:{
    
    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}>当前求和为奇数再加</button>&nbsp;
          <button onClick={
    
    this.incrementAsync}>异步加</button>&nbsp;
        </div>
      )
    }

  }

  //使用connect()()创建并暴露一个Count的容器组件
  //使用connect(传入状态,操作状态方法)(UI组件)
  export default connect(
    state => ({
    
    
      count: state.count,
      personCount: state.persons.length
    }),
    {
    
    increment, decrement, incrementAsync}
  )(Count)
  1. Person文件夹下的jsx
  import React, {
    
     Component } from 'react'
  import {
    
     connect } from 'react-redux'
  import {
    
     addPerson } from '../../redux/actions/person'
  import {
    
     nanoid } from 'nanoid'
  //创建UI组件
  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>我是Person组件,上方组件求和为{
    
    this.props.count}</h2>
          <input ref={
    
    c => this.nameNode = c} type="text" placeholder="输入名字" />
          <input ref={
    
    c => this.ageNode = c} type="text" placeholder="输入年龄" />
          <button onClick={
    
    this.addPerson}>添加</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
    }), {
    
     addPerson }
  )(Person)

猜你喜欢

转载自blog.csdn.net/m0_55644132/article/details/127875727