reducer工程化
1.reducer的拆分和合并
// vote版块下的reducer
const initial = {
supNum: 10,
oppNum: 5,
num: 0
}
export default function voteReducer(state = initial, action) {
// 深克隆
state = { ...state }
switch(action.type) {
case 'VOTE_SUP':
state.supNum++
break
case 'VOTE_OPP':
state.oppNum++
break
default:
break
}
return state
}
// Personal版块下的reducer
const initial = {
num: 100,
info: null
}
export default function PersonalReducer(state = initial, action) {
// 深克隆
state = { ...state }
switch(action.type) {
case 'PERSONAL_INFO':
state.info = action.info
break
default:
break
}
return state
}
// 合并各个模块的reducer
import { combineReducers } from 'redux'
import voteReducer from './VoteReducer'
import PersonalReducer from './PersonalReducer'
const reducer = combineReducers({
vote: voteReducer,
personal: PersonalReducer
})
export default reducer
/*
state = {
vote: {
supNum: 10,
oppNum: 5,
num: 0
},
personal: {
nun: 100,
info: null
}
}
*/
1.1combineReducers源码分析
export default function myCombineReducers(reducers) {
// reducers是一个对象,以键值对存储了:模块名:每个模块的reducer
let reducersKeys = Reflect.ownKeys(reducers)
/*
返回一个合并的reducer
+ 每次dispatch派发,都要把这个reducer执行
+ state就是redux容器中的公共状态
+ action就是派发时候传递进来的行为对象
*/
return function reducer(state = {}, action) {
// 把reducers中的每个模块中的reducer执行
let nextState = {}
reducersKeys.forEach(key => {
let reducer = reducers[key]
nextState[key] = reducer(state[key], action)
})
}
}
2.派发行为标识宏管理
问题:每一次dispatch派发的时候,都会去每个模块的reducer中找一遍,把所有和派发行为标识匹配的逻辑执行,很可能由于派发的行为的标识名称相同导致冲突
解决办法:基于宏管理(统一管理),让所有派发的行为标识,具有唯一性
统一管理需要派发的行为标识
- 为了保证不冲突,我们一般都是这么命名的:模块名__派发的行为标识(大写)
- 变量和存储的值是一致的
- 所以需要派发的行为标识,都在这里定义
export const VOTE_SUP = "VOTE_SUP"
export const VOTE_OPP = "VOTE_OPP"
export const PERSONAL_SUP = "PERSONAL_SUP"
export const PERSONAL_INFO = "PERSONAL_INFO"
3.actionCreator的创建
把派发的行为对象按照模块进行统一管理
import * as TYPES from '../action_types'
// vote板块要派发的行为对象管理
const voteAction = {
support() {
return {
type: TYPES.VOTE_SUP
}
},
oppose() {
return {
type: TYPES.VOTE_OPP
}
}
}
export default voteAction
import * as TYPES from '../action_types'
// personal板块要派发的行为对象管理
const personalAction = {
getInfo() {
return {
type: TYPES.PERSONAL_INFO
}
},
}
export default personalAction
// 把各个板块的action合并为一个action
import voteAction from "./voteAction";
import personalAction from "./personalAction";
const action = {
vote: voteAction,
personal: personalAction
}
export default action
react-redux的基础运用
1、提供provider方法传递上下文对象
import { Provider } from 'react-redux'
<Provider store={store}>
<Vote />
</Provider>
2、提供connect函数获取公共状态信息绑定
/*
connect(mapStateToProps, mapDispatchProps)(我们要渲染的组件
1.mapStateToProps:可以获取到redux中的公共状态,把需要的信息作为属性传递给组件
connect((state) => {
// 存储redux容器中,所有模块的公共状态信息
// 返回对象中的信息,就是要作为属性,传递给组件信息
return {
supNum: state.vote.supNum,
info: state.personal.info
}
})(Vote)
2.mapDispatchProps:把需要派发的任务,当作属性传递给组件
connect(null,
dispatch => {
// dispatch:store.dispatch
// 返回对象中的信息,会作为属性传递给组件
return {
}
})(Vote)
*/
// 传递公共状态
export default connect(state => {
return {
supNum: state.vote.supNum,
oppNum: state.vote.oppNum,
num: state.vote.num
}
})(Vote)
const Vote = function Vote(props) {
let { supNum, oppNum } = props
}
// 传递派发的任务
export default connect(null, dispatch => {
return {
support() {
dispatch(action.vote.support())
},
oppose() {
dispatch(action.vote.oppose())
}
}
})(VoteFooter)
let { support, oppose } = props
解析react-redux源码
import React, { createContext, useContext, useEffect, useMemo, useState } from 'react'
import { bindActionCreators } from 'redux'
const ThemeContext = createContext()
export function Provider(props) {
let { store, children } = props
return <ThemeContext.Provider value={{ store: store }}>
{children}
</ThemeContext.Provider>
}
export function connect(mapStateToProps, mapDispatchToProps) {
if (!mapStateToProps) {
mapStateToProps = () => {
// 默认什么都不传递给组件
return {}
}
}
if (!mapDispatchToProps) {
mapDispatchToProps = (dispatch) => {
// 默认传递dispatch方法给组件
return {
dispatch
}
}
}
return function currying(Component) {
// Component: 最终要渲染的组件
return function HOC(props) {
// 需要获取上下文中的store
let { store } = useContext(ThemeContext),
{ getState, dispatch, subscribe } = store
// 向事件池中加入让组件更新的方法
let [, forceUpdate] = useState(0)
useEffect(() => {
let unsubscribe = subscribe(() => {
forceUpdate(+new Date())
})
return () => {
// 组件释放的时候执行: 把事件池中的函数移除掉
unsubscribe()
}
}, [])
// 把mapStateToProps和mapDispatchToProps执行,把执行的返回值作为属性传递给组件
let state = getState(),
nextState = useMemo(() => {
mapStateToProps(state)
}, [state])
let dispatchProps = {}
if (typeof mapDispatchToProps === 'function') {
// 是函数直接执行即可
dispatchProps = mapDispatchToProps(dispatch)
} else {
// 是actionCreator对象,需要经过bindActionCreators处理
dispatchProps = bindActionCreators(mapDispatchToProps, dispatch)
}
return <Component {...props} {...nextState} {...dispatchProps} />
}
}
}