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