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

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

之前,我们的求和案例只是一个组件,属于是自己玩自己,接下来我们通过多个组件,通过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里面的逻辑。


步骤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,要“取到位”。

相关文章
|
6月前
|
JavaScript API
Vuex状态管理最佳实践
使用Vuex进行状态管理时,有一些最佳实践可以帮助你保持代码清晰、可维护和高效。以下是一些详细的Vuex状态管理最佳实践
|
3月前
|
存储 JavaScript 前端开发
【第36期】一文学会Redux状态管理
【第36期】一文学会Redux状态管理
58 0
|
6天前
|
JavaScript 测试技术
状态管理:集成 Vuex 进行全局状态管理
【4月更文挑战第22天】Vuex 是 Vue.js 的状态管理库,通过状态、mutations、actions 和 modules 等核心概念集中管理应用状态。创建 store,划分模块以增强代码维护性。mutations 同步改变状态,actions 处理异步逻辑。遵循 Vuex 规范,在组件中使用辅助函数访问状态。有效更新和处理错误,实现与其它工具集成,提升应用性能和可靠性。注意根据项目需求灵活使用,防止状态管理过度复杂。
|
3月前
|
JavaScript 程序员
状态管理之Vuex (二) 异步管理
状态管理之Vuex (二) 异步管理
14 0
|
10月前
|
存储 小程序 JavaScript
再也不用担心组件跨层级的数据共享和方法驱动了
再也不用担心组件跨层级的数据共享和方法驱动了
86 0
|
11月前
|
存储 缓存 前端开发
从 Signals 看响应式状态管理
从 Signals 看响应式状态管理
175 0
|
小程序 JavaScript
【小程序】全局数据共享
【小程序】全局数据共享
184 0
【小程序】全局数据共享
|
前端开发 JavaScript 安全
一个很简单理解的轻量级状态管理
本文适合对状态管理感兴趣的小伙伴阅读。
一个很简单理解的轻量级状态管理
|
前端开发 开发者
介绍有状态组件和无状态组件的区别|学习笔记
快速学习介绍有状态组件和无状态组件的区别
139 0
|
前端开发
介绍有状态组件和无状态组件的区别
介绍有状态组件和无状态组件的区别