第三十五章 多个组件状态数据共享

之前,我们的求和案例只是一个组件,属于是自己玩自己,接下来我们通过多个组件,通过redux实现它们之间的数据互通。

步骤1:更改项目目录结构

src
|--containers
|	|--Count
|--redux
|	|--actions
|		|--count.js
|	|--reducers
|		|--count.js
|	|--constant.js
|	|--store.js
|--App.jsx
|--index.js

由于我们现在要实现多个组件的状态共享,需要划分更细致的文件分类,以供我们更好的维护项目。

  • 将原来的count_action.js=变为=> redux/actions/count.js
  • 将原来的count_reducer.js=变为=> redux/reducers/count.js
  • 其他文件相应的导入路径也要做相应的修改,这里不在赘述。

步骤2:新建一个Person组件

文件:src/containers/Person/index.jsx

import React, {
    
     Component } from 'react'
import {
    
    nanoid} from 'nanoid'

export default class Person extends Component {
    
    

  addPerson = () => {
    
    
    const {
    
     nameNode, ageNode } = this
    const person = {
    
    
      id: nanoid(),
      name: nameNode.value,
      age: ageNode.value * 1
    }
    console.log(person)
  }

  render() {
    
    
    return (
      <div>
        <h1>Person组件,上方组件求和为:{
    
    this.props.sum}</h1>
        <input type="text" placeholder='请输入姓名' ref={
    
    c => this.nameNode = c} />&nbsp;
        <input type="text" placeholder='请输入年龄' ref={
    
    c => this.ageNode = c} />&nbsp;
        <button onClick={
    
    this.addPerson}>添加</button>
        <h2>人员列表</h2>
        <ul>
          <li>姓名1--年龄</li>
        </ul>
      </div>
    )
  }
}

然后引入到App组件里面

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

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

效果如下:

在这里插入图片描述


步骤3:编写Person组件相关的redux文件

(1). 新增常量类型:ADD_PERSON

// src/redux/constant.js
// 该模块是用于定义action对象的type类型的常量值
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
export const ADD_PERSON = 'add_person'

(2). 新增person的action文件

// src/redux/actions/person.js
import {
    
     ADD_PERSON } from '../constant'
// 添加人信息的action
export const createAddPersonAction = personObj => ({
    
    type: ADD_PERSON, data:personObj})

(3). 新增person的reducer文件

// src/redux/reducers/person.js
import {
    
    ADD_PERSON} from '../constant'

const initData = [{
    
    id:'001',name:'tom',age:18}]
export default function personReducer (preState = initData, action) {
    
    
  // 获取type和data
  const {
    
    type,data} = action

  switch (type) {
    
    
    case ADD_PERSON:
      return [data,...preState]
  
    default:
      return preState
  }
}

(4). 融合Person的容器组件

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 {
    
     nameNode, ageNode } = this
    const person = {
    
    
      id: nanoid(),
      name: nameNode.value,
      age: ageNode.value * 1
    }
    console.log(person)
  }

  render() {
    
    
    return (
      <div>
        <h1>Person组件</h1>
        <input type="text" placeholder='请输入姓名' ref={
    
    c => this.nameNode = c} />&nbsp;
        <input type="text" placeholder='请输入年龄' ref={
    
    c => this.ageNode = c} />&nbsp;
        <button onClick={
    
    this.addPerson}>添加</button>
        <h2>人员列表</h2>
        <ul>
          <li>姓名1--年龄</li>
        </ul>
      </div>
    )
  }
}

export default connect(
  state => ({
    
    peoList:state}), // 映射状态
  {
    
    } // 映射操作状态的方法
)(Person)

至此,我们对Person组件的redux相关代码已经七七八八了,但是现在并不起作用,因为我们的store并没有使用到personreducer里面的逻辑。

扫描二维码关注公众号,回复: 17187609 查看本文章

步骤4:整改store文件内容

// 引入createStore,专门用于创建redux中最为核心的store对象
import {
    
     createStore , applyMiddleware } from 'redux'
import countReducer from './reducers/count'
// 引入redux-thunk,用于支持异步action
import thunk from 'redux-thunk'

export default createStore(countReducer,applyMiddleware(thunk))


根据代码,我们知道这里没有引入Person相关的reducer,那我们该如何使用呢?

答案是:引入一个新的API合并多个reducer===>combineReducers

combineReducers是一种常用的组合Reducer的方法,它可以使代码更加简洁和易于维护。

// 引入createStore,专门用于创建redux中最为核心的store对象
import {
    
     createStore , applyMiddleware, combineReducers } from 'redux'
import countReducer from './reducers/count'
import personReducer from './reducers/person'
// 引入redux-thunk,用于支持异步action
import thunk from 'redux-thunk'

const allReducer = combineReducers({
    
    
  sum: countReducer,
  peoples: personReducer
})
export default createStore(allReducer,applyMiddleware(thunk))

以上就是我们修改后的完整版的store文件了,这里我们使用combineReducers这个APICount组件和Person组件的reducer进行了合并,形成了一个新的allReducer将它传递给createStore这个API


步骤5:在Person组件里面将数据存入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 {
    
     nameNode, ageNode } = this
    const person = {
    
    
      id: nanoid(),
      name: nameNode.value,
      age: ageNode.value * 1
    }
    // console.log(person)
    this.props.addPeople(person)
  }

  render() {
    
    
    return (
      <div>
        <h1>Person组件</h1>
        <input type="text" placeholder='请输入姓名' ref={
    
    c => this.nameNode = c} />&nbsp;
        <input type="text" placeholder='请输入年龄' ref={
    
    c => this.ageNode = c} />&nbsp;
        <button onClick={
    
    this.addPerson}>添加</button>
        <h2>人员列表</h2>
        <ul>
          {
    
    
            this.props.peoList.map((p)=>{
    
    
              return <li key={
    
    p.id}>{
    
    p.name}--{
    
    p.age}</li>
            })
          }
        </ul>
      </div>
    )
  }
}

export default connect(
  state => ({
    
    peoList:state.peoples}), // 映射状态
  {
    
    addPeople:createAddPersonAction} // 映射操作状态的方法
)(Person)

查看效果:
在这里插入图片描述


步骤6:两个组件相互引入redux里面是状态数据

文件:Person/index.jsx

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 {
    
     nameNode, ageNode } = this
    const person = {
    
    
      id: nanoid(),
      name: nameNode.value,
      age: ageNode.value * 1
    }
    // console.log(person)
    this.props.addPeople(person)
  }

  render() {
    
    
    return (
      <div>
        <h1>Person组件,上方组件求和为:{
    
    this.props.sum} </h1>
        <input type="text" placeholder='请输入姓名' ref={
    
    c => this.nameNode = c} />&nbsp;
        <input type="text" placeholder='请输入年龄' ref={
    
    c => this.ageNode = c} />&nbsp;
        <button onClick={
    
    this.addPerson}>添加</button>
        <h2>人员列表</h2>
        <ul>
          {
    
    
            this.props.peoList.map((p)=>{
    
    
              return <li key={
    
    p.id}>{
    
    p.name}--{
    
    p.age}</li>
            })
          }
        </ul>
      </div>
    )
  }
}

export default connect(
  state => ({
    
    peoList:state.peoples,sum:state.sum}), // 映射状态
  {
    
    addPeople:createAddPersonAction} // 映射操作状态的方法
)(Person)

文件:Count/index.jsx

// 引入action
import {
    
    
  createIncrementAction,
  createDecrementAction,
  createIncrementAsyncAction
} from '../../redux/actions/count'

// 引入react-redux中的connect用于连接UI组件和容器组件
import {
    
     connect } from 'react-redux'
import React, {
    
     Component } from 'react'

class Count extends Component {
    
    

  increment = () => {
    
    
    // 普通加
    // 1、获取用户选择的值
    const {
    
     value } = this.selectNumber
    this.props.jia(value*1)
  }

  decrement = () => {
    
    
    // 普通减
    // 1、获取用户选择的值
    const {
    
     value } = this.selectNumber
    this.props.jian(value*1)
  }

  incrementIfOdd = () => {
    
    
    // 当前求和为奇数为
    // 1、获取用户选择的值
    const {
    
     value } = this.selectNumber
    if (this.props.count %2 !== 0) {
    
    
      this.props.jia(value*1)
    }
  }

  incrementAsync = () => {
    
    
    // 异步加
    // 1、获取用户选择的值
    const {
    
     value } = this.selectNumber
    this.props.jiaAsync(value*1,500)
  }

  render() {
    
    
    return (
      <div>
        <h1>当前求和为:{
    
    this.props.count},下方组件人数为{
    
    this.props.peoLens}</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}>当前求和为奇数为</button>&nbsp;
        <button onClick={
    
    this.incrementAsync}>异步加</button>&nbsp;
      </div>
    )
  }
}


// 创建并暴露一个容器组件
export default connect(
  state => ({
    
    count: state.sum, peoLens: state.peoples.length}),
  {
    
    
    jia:createIncrementAction,
    jian:createDecrementAction,
    jiaAsync:createIncrementAsyncAction
  }
  )(Count)

整体效果:

在这里插入图片描述


总结

(1). 定义一个Person组件,和Count组件通过redux共享数据

(2). 为Person组件编写reduceraction,配置constant常量

(3). 重点:PersonreducerCountReducer要使用combineReducer进行合并,合并后的总状态是一个对象!

(4). 交给store的是总reducer,最后注意在组件取出状态的时候,记得是对应的keyvalue,要“取到位”。

猜你喜欢

转载自blog.csdn.net/qq_36362721/article/details/130762159