之前,我们的求和案例只是一个组件,属于是自己玩自己,接下来我们通过多个组件,通过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} />
<input type="text" placeholder='请输入年龄' ref={c => this.ageNode = c} />
<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} />
<input type="text" placeholder='请输入年龄' ref={c => this.ageNode = c} />
<button onClick={this.addPerson}>添加</button>
<h2>人员列表</h2>
<ul>
<li>姓名1--年龄</li>
</ul>
</div>
)
}
}
export default connect(
state => ({peoList:state}), // 映射状态
{} // 映射操作状态的方法
)(Person)
至此,我们对Person
组件的redux
相关代码已经七七八八了,但是现在并不起作用,因为我们的store
并没有使用到person
的reducer
里面的逻辑。
步骤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
这个API
将Count
组件和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} />
<input type="text" placeholder='请输入年龄' ref={c => this.ageNode = c} />
<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} />
<input type="text" placeholder='请输入年龄' ref={c => this.ageNode = c} />
<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>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>当前求和为奇数为</button>
<button onClick={this.incrementAsync}>异步加</button>
</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
组件编写reducer
、action
,配置constant
常量
(3). 重点:Person
的reducer
和Count
的Reducer
要使用combineReducer
进行合并,合并后的总状态是一个对象!
(4). 交给store
的是总reducer
,最后注意在组件取出状态的时候,记得是对应的key
和value
,要“取到位”。