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

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

之前,我们的求和案例只是一个组件,属于是自己玩自己,接下来我们通过多个组件,通过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,要“取到位”。

相关文章
|
缓存 JavaScript 前端开发
看完这篇文章,不再害怕Vue3的源码(二)
看完这篇文章,不再害怕Vue3的源码
|
JavaScript 前端开发 编译器
看完这篇文章,不再害怕Vue3的源码(一)
看完这篇文章,不再害怕Vue3的源码
|
前端开发 JavaScript 安全
|
存储 缓存 JavaScript
Vue3实现页面缓存
【10月更文挑战第9天】
813 121
|
前端开发 JavaScript 测试技术
React 中集成 Chart.js 图表库
本文介绍了如何在 React 项目中集成 Chart.js 创建动态图表,涵盖基础概念、安装步骤、代码示例及常见问题解决方法,帮助开发者轻松实现数据可视化。
388 11
|
算法
记一次requests.get()返回数据乱码问题
【10月更文挑战第21天】使用`requests.get()`请求网页时遇到乱码问题,尝试通过设置`encoding`和使用`apparent_encoding`自动判断编码均无效。最终发现问题是由于请求头中的`Accept-Encoding`包含了`br`(Brotli压缩格式),导致响应内容未被正确解压。移除`Accept-Encoding`中的`br`后,问题得到解决。
464 7
|
JavaScript 前端开发 应用服务中间件
Vue3 + Vite + TypeScript + Element-Plus:从零到一构建企业级后台管理系统(前后端开源)(2)
Vue3 + Vite + TypeScript + Element-Plus:从零到一构建企业级后台管理系统(前后端开源)(2)
|
Web App开发 存储 安全
就一次!带你彻底搞懂CSRF攻击与防御
与XSS攻击相比,利用CSRF漏洞发动攻击会比较困难,这也是在网络上看起来CSRF的人气小于XSS的原因之一。下面我们来利用CSRF漏洞发起攻击,并针对攻击进行防御,彻底弄懂CSRF,话不多说,我们直接开冲。
|
JavaScript
详细讲解JS的解构赋值(Es6)
详细讲解JS的解构赋值(Es6)
|
存储 缓存 资源调度
Monorepo(单体仓库)与MultiRepo(多仓库): Monorepo 单体仓库开发策略与实践指南
Monorepo(单体仓库)与MultiRepo(多仓库): Monorepo 单体仓库开发策略与实践指南
1234 0