前言
经过react-redux的学习已经了解了store基础操作,但是在实际开发过程中是多个组件之间进行数据共享。action、reducer、store是redux操作的核心。一般我们在constant里对type变量进行封装,action、reducer都需要它。
- UI组件:在这里我们先进行组件渲染,把可能发生的动作记录下来。
- 容器组件:负责和redux通信和状态更新,为了简化操作,可将UI组件整合到容器组件中,最后暴露容器组件即可。容器组件又是通过connect与UI组件建立连接,所有容器组件为父组件,UI组件获得容器组件传来的数据通过props即可
- action: 根据type,找到reducer里的具体数据操作
- reducer: 用于初始化和加工状态。reducer为纯函数
- store对象:整个应用只要一个store对象,所以直接在入口文件 index.js通过 provider将store传递给整个应用。
import store from "./redux/store"
<Provider store={store}>
<App />
</Provider>
一、多组件数据共享
1.1 容器组件
1.1 Count容器组件
import React, { Component } from "react"
import "./index.css"
- Count
import React, { Component } from "react"
import "./index.css"
//引入connect用于连接UI组件和redux store
import { connect } from "react-redux"
class CountUI extends Component {
addNum = () => {
// const { value } = this.selectNumber
}
//减法
subNum = () => {
// const { value } = this.selectNumber
}
//奇数加
addNumIfodd = () => {}
//异步加
addNumAsync = () => {
// const { value } = this.selectNumber
}
render() {
return (
<div>
<h3>
Count组件
<span style={{ marginLeft: "30px" }}>person总人数:</span>
</h3>
<h3>
当前求和为:<span></span>
</h3>
<select
name="select"
id=""
ref={(c) => (this.selectNumber = c)}
>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.addNum}>+</button>
<button onClick={this.subNum}>-</button>
<button onClick={this.addNumIfodd}>当前求和为奇数加</button>
<button onClick={this.addNumAsync}>异步加</button>
</div>
)
}
}
export default connect()(CountUI)
1.2 Person容器组件
- Person
import React, { Component } from "react"
import { nanoid } from "nanoid"
import "./index.css"
import { connect } from "react-redux"
class PersonUI extends Component {
addPerson = () => {
const name = this.nameNode.value
const age = this.ageNode.value
const perobj = { id: nanoid(), name, age }
console.log(perobj)
// this.nameNode.value = ""
// this.ageNode.value = ""
}
render() {
return (
<div>
<h3>
Person组件
<span style={{ marginLeft: "30px" }}>count组件的和:</span>
</h3>
<input
ref={(c) => (this.nameNode = c)}
type="text"
placeholder="输入名字"
/>
<input
ref={(c) => (this.ageNode = c)}
type="text"
placeholder="输入年龄"
/>
<button onClick={this.addPerson}>添加</button>
<ul>
<li>----姓名:----年龄:</li>
</ul>
</div>
)
}
}
export default connect()(PersonUI)
1.2 constant.js
该模块式用于定义type类型的常量值。Count容器组件,add和sub;Person容器组件addperson
export const ADD = "add"
export const SUB = "sub"
export const ADDPERSON = "addperson"
1.3 redux
1.3.1 actions
- count.js
import { ADD, SUB } from "../constant"
export const add = (data) => ({
type: ADD,
data,
})
export const sub = (data) => ({
type: SUB,
data,
})
- 异步Action,也就是返回值为函数,且能开启异步任务
- 异步Action一般都会调用同步Action
- 异步Action不是必须要用的
export const addAsync = (data, time) => { return (dispatch) => { //异步任务 setTimeout(() => { dispatch(add(data)) }, time) } }
- person.js
import { ADDPERSON } from "../constant"
export const addPerson = (perobj) => ({
type: ADDPERSON,
data: perobj,
})
1.3.2 reducers
- count.js
import { ADD, SUB } from "../constant"
const initState = 0
export default function countReducer(preState = initState, action) {
const { type, data } = action
//根据type决定如何加工数据
switch (type) {
case ADD:
return preState + data
case SUB:
return preState - data
default:
return preState
}
}
- person.js
import { ADDPERSON } from "../constant"
//初始化列表
const initState = [{ id: "001", name: "Tom", age: 18 }]
export default function personReducer(preState = initState, action) {
const { type, data } = action
switch (type) {
case ADDPERSON:
return [data, ...preState]
default:
return preState
}
}
redux的reducer函数必须是一个纯函数
什么是纯函数?
1) 不得改写参数数据
2) 不会产生任何副作用,例如网络请求,输入和输出设备
3) 不能调用Date.now()或者Math.random()等不纯的方法
- index.js
该文件用于汇总reducer,combineReducers传入的对象,就是reducer里保存的总状态对象
import count from "./count"
import persons from "./person"
import { combineReducers } from "@reduxjs/toolkit"
export default combineReducers({
count,
persons,
})
1.4 store
import { configureStore } from "@reduxjs/toolkit"
//引入汇总后的reducer
import reducer from "./reducers/index"
export default configureStore({
reducer,
})
至此,store的初始加工完成,接下来要在容器组件中对数据进行加工
1.5 加工数据
connect(映射状态)(映射操作状态的方法)(关联组件)
- Count容器
state.count和 state.persons 是store定义的,react-redux会帮我们自动dispatch所属的action。然后根据action的type找到对应的数据处理逻辑,,并把action携带的数据带走。因为又是所属容器,UI组件调用需要通过props。
export default connect(
// state总状态
(state) => ({ count: state.count, perlen: state.persons.length }),
// mapDispatchToProps简写 react-dedux帮自动分发
{
add,
sub,
addAsync,
}
)(CountUI)
addNum = () => {
const { value } = this.selectNumber
this.props.add(value * 1)
}
//减法
subNum = () => {
const { value } = this.selectNumber
this.props.sub(value * 1)
}
//奇数加
addNumIfodd = () => {
//如何获取count
const { count } = this.props
if (count % 2 !== 0) {
this.addNum()
}
}
//异步加
addNumAsync = () => {
const { value } = this.selectNumber
this.props.addAsync(value * 1, 500)
}
Count组件和、Person组件人数和通过props获取
const { count, perlen } = this.props
- Person容器
import { nanoid } from "nanoid"
export default connect((state) => ({ obj: state.persons, sum: state.count }), {
addPerson,
})(PersonUI)
addPerson = () => {
const name = this.nameNode.value
const age = this.ageNode.value * 1
// console.log(name, age)
const perobj = { id: nanoid(), name, age }
//console.log(perobj)
this.props.addPerson(perobj)
this.nameNode.value = ""
this.ageNode.value = ""
}
Count组件和
const { sum } = this.props