[React] 14 - Redux: add more components
基本开发流程 (针对一个组件)
- 第二步
he的初始值;this.add调用的对应方法jiafa;
注意:createIncrementAction 是action中在定义(了个“dict")
state, createIncrementAction的具体操作则都在reducer中提前定义好。
//加法 increment = ()=>{ const {value} = this.selectNumber this.props.jia(value*1) }
添加 Person 组件
./redux/actions/xxx.js ./redux/reducers/xxx.js
[第一步] 先各自定义两个 “独立” 的部分:UI 与 逻辑。
-
-
定义好了 “UI部分”
-
注意:state部分 是与Count 共享了 he这个状态。毕竟大家都用着同一个store。
containers/Person/index.jsx
class Person extends Component { addPerson_onClick = ()=>{ const name = this.nameNode.value const age = this.ageNode.value
const personObj = {id:nanoid(), name, age}
this.props.jiaYiRen(personObj) } render() { return ( <div> <h2>我是Person组件,上方组件求和为{this.props.he}</h2> // <------- 共享的部分~ <input ref={c=>this.nameNode = c} type="text" placeholder="输入名字"/> <input ref={c=>this.ageNode = c} type="text" placeholder="输入年龄"/> <button onClick={this.addPerson_onClick}>添加</button> <ul> { this.props.yiduiren.map((p)=>{ return <li key={p.id}>{p.name}--{p.age}</li> }) } </ul> </div> ) } }
// 以上应该没任何 redux 东西,只专注于 UI部分~
export default connect( state => ({yiduiren:state.rens, he:state.he}), // 映射状态 --> mapStateToProps {jiaYiRen:createAddPersonAction} // 映射操作状态的方法 --> mapDispatchToProps(需在下一步定义createAddPersionAction的format) )(Person)
-
-
定义好了 “逻辑部分”
-
重点理解:上面的 createAddPersonAction 定义好了 “数据包”;但这个包如何传递到下面的 persionReducer's parameter?
redux/reducers/person.js
import {ADD_PERSON} from '../constant' //初始化人的列表 const initState = [{id:'001',name:'tom',age:18}] export default function personReducer(preState=initState, action){ // console.log('personReducer@#@#@#'); const {type, data} = action switch (type) { case ADD_PERSON: return [data,...preState] // ----> 纯函数 default: return preState } }
import {INCREMENT,DECREMENT} from '../constant' const initState = 0 //初始化状态 export default function countReducer(preState=initState,action){ // console.log('countReducer@#@#@#'); //从action对象中获取:type、data const {type,data} = action //根据type决定如何加工数据 switch (type) { case INCREMENT: //如果是加 return preState + data case DECREMENT: //若果是减 return preState - data default: return preState } }
7.8.1. 纯函数
一类特别的函数: 只要是同样的输入(实参),必定得到同样的输出(返回)
必须遵守以下一些约束
不得改写参数数据
不会产生任何副作用,例如网络请求,输入和输出设备
不能调用Date.now()或者Math.random()等不纯的方法
redux的reducer函数必须是一个纯函数
7.8.2. 高阶函数
理解: 一类特别的函数
情况1: 参数是函数
情况2: 返回是函数
常见的高阶函数:
定时器设置函数
数组的forEach()/map()/filter()/reduce()/find()/bind()
promise
react-redux中的connect函数
作用: 能实现更加动态, 更加可扩展的功能
[第二步] 作为“粘和”,这需要定义 消息的格式,以及调度者也需支持这个格式。
-
-
action
-
UI组件 涉及的两个地方,其中之一就是简单的定义了action 的消息格式,在如下定义。
./redux/actions/person.js
import {ADD_PERSON} from '../constant' //创建增加一个人的action动作对象 export const createAddPersonAction = personObj => ({type:ADD_PERSON, data:personObj})
/* 该文件专门为Count组件生成action对象 */ import {INCREMENT,DECREMENT} from '../constant' //同步action,就是指action的值为Object类型的一般对象 export const createIncrementAction = data => ({type:INCREMENT,data}) export const createDecrementAction = data => ({type:DECREMENT,data}) //异步action,就是指action的值为函数,异步action中一般都会调用同步action,异步action不是必须要用的。 export const createIncrementAsyncAction = (data,time) => { return (dispatch)=>{ setTimeout(()=>{ dispatch(createIncrementAction(data)) },time) } }
-
-
store
-
另一部分的state定义在reducer中。Why? 因为reducer中定义了 initState。指定了reducer,也就是指定了state。
./redux/store.js
//汇总所有的reducer变为一个总的reducer const allReducer = combineReducers({ he:countReducer, rens:personReducer }) //暴露store export default createStore(allReducer, applyMiddleware(thunk))
Redux Tool
npm install --save-dev redux-devtools-extension
//引入redux-devtools-extension import {composeWithDevTools} from 'redux-devtools-extension' //汇总所有的reducer变为一个总的reducer const allReducer = combineReducers({ he:countReducer, rens:personReducer }) //暴露store export default createStore( allReducer, composeWithDevTools(applyMiddleware(thunk)) )
安装包,并引用。
大总结
各个注意点
1. 用Provider包裹App,目的是让App所有的后代容器组件都能接收到store。
import React from 'react' import ReactDOM from 'react-dom' import App from './App' import store from './redux/store' import {Provider} from 'react-redux' ReactDOM.render( /* 此处需要用Provider包裹App,目的是让App所有的后代容器组件都能接收到store */ <Provider store={store}> <App/> </Provider>, document.getElementById('root') )
2. 引入的是“容器组件”,而非UI组件。
import React, { Component } from 'react' import Count from './containers/Count' //引入的Count的容器组件 import Person from './containers/Person' //引入的Person的容器组件 export default class App extends Component { render() { return ( <div> <Count/> <hr/> <Person/> </div> ) } }
3. 采用js对象的简写方式。
./containers/Person/index.js
import React, { Component } from 'react' import {nanoid} from 'nanoid' import {connect} from 'react-redux' import {addPerson} from '../../redux/actions/person' class Person extends Component { addPerson_onClick = ()=>{ const name = this.nameNode.value const age = this.ageNode.value*1 const personObj = {id:nanoid(),name,age} this.props.addPerson(personObj) this.nameNode.value = '' this.ageNode.value = '' } render() { return ( <div> <h2>我是Person组件,上方组件求和为{this.props.count}</h2> <input ref={c=>this.nameNode = c} type="text" placeholder="输入名字"/> <input ref={c=>this.ageNode = c} type="text" placeholder="输入年龄"/> <button onClick={this.addPerson_onClick}>添加</button> <ul> { this.props.persons.map((p)=>{ return <li key={p.id}>{p.name}--{p.age}</li> }) } </ul> </div> ) } } export default connect( state => ({ persons:state.persons, count:state.count }), // 映射状态 {addPerson} // 映射操作状态的方法 )(Person)
4. store引入一个 "作为汇总的reducer“ 即可。
./redux/reducers/index.js
import count from './count' import persons from './person' //汇总所有的reducer变为一个总的reducer export default combineReducers({ count, persons })