Redux
状态管理的东西还是挺多的,所以分成几个步骤去理解
store
说明: 状态管理,状态管理,所以必须要有一个仓库对象,先看一下这个对象的结构
{
dispatch, // 更改state
subscribe, // 监听state变化
getState, // 数据
... // 个人觉得这几个不重要
}
reducer
function reducer(state = initState, action) {
// 接受state, action,更新state
if (action.type === 'demo')
return {
...state,
value: 'val'
}
}
createStore
说明: store由这个创建;
function createStore(reducer, preloadedState, enhancer) {
// 中间件, 后面说明
if (typeof enhancer !== 'undefined') enhancer(createStore)(reducer, preloadedState)
let currentReducer = reducer
let currentState = preloadedState
let listeners = [] // 监听state变化的回调
function getState() {
return currentState
}
// subscribe 返回一个 unsubscribe 函数,用来删除这个回调
function subscribe(listener) {
// listeners.push(listener)
// 删除回调
return function unsubscribe() {
const index = listeners.indexOf(listener)
listeners.splice(index, 1)
}
}
// 更改 state 的唯一方式
function dispatch(action) {
currentState = currentReducer(currentState, action)
// 触发回调
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener()
}
return action
}
// 执行 reducer 初始化state
dispatch({ type: INIT })
return {
dispatch,
subscribe,
getState,
...
}
}
combineReducers
说明: 项目数据多需要拆分模块, 通过combineReducers,将多个reducer组合成一个;
/*
{
key1: reducer1,
key2: reducer2,
key3: reducer3,
}
{
key1: reducer1(state = {}, action)
}
*/
const combineReducers = reducers => {
return (state, action) => {
const nextState = {}
for (const key in reducers) {
if (Object.hasOwnProperty.call(reducers, key)) {
const reducer = reducers[key]
nextState[key] = reducer(state[key], action)
}
}
return nextState
}
}
Provider
说明:有了这个 store 自然就需要应用到系统中;
// <Provider store={store} />
class Provider extends Component {
constructor(props) {
super(props)
const { store } = props
// Provider 的state
this.state = {
reduxState: store.getState(),
store
}
}
componentDidMount() {
this.subscribe() // 注册监听, state更改的时候重新渲染应用
}
componentWillUnmount() {
if (this.unsubscribe) this.unsubscribe() // 取消监听
}
subscribe() {
// 更改state重新渲染应用
this.unsubscribe = store.subscribe(() => {
this.setState(() => ({ reduxState: store.getState() }))
})
// 如果在componentDidMount之前就dispatch了,需要重新渲染一遍应用
if (store.getState() !== this.state.reduxState) {
this.setState({ reduxState: store.getState() })
}
}
render() {
return (
// 传递给 connect
<ReactReduxContext.Provider value={this.state}>
{this.props.children}
</ReactReduxContext.Provider>
)
}
}
connect
说明: 你自己的组件肯定不能每个都通过获取 ReactReduxContext,所以需要一个高阶组件帮你包一下
const connect = (mapStateToProps) => (WrappedComponent) => {
class Connect extends Component {
constructor () {
super()
// 传递给子组件,state变化时,触发重新渲染
this.state = { childProps: {} }
}
componentWillMount () {
const { store } = this.context
this._updateProps()
// 监听state变化
store.subscribe(() => this._updateProps())
}
_updateProps () {
const { store } = this.context
this.setState({
childProps: {
...mapStateToProps(store.getState(), this.props),
dispatch: store.dispatch,
...this.props
}
})
}
render () {
return <WrappedComponent {...this.state.childProps} />
}
}
return Connect
}
compose
说明: 聚合函数,作用就类似洋葱模型一样;
function compose(funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
enhancer
说明:利用中间件,强化你的 dispatch;
// applyMiddleware(...middlewares)(createStore)(reducer, initState)
function applyMiddleware(...middlewares) {
return createStore => (...args) => {
// 1. 创建 store
const store = createStore(...args)
let chain = []
// 2. 每个中间件都应该有这两个函数
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args)
}
// 3. 给中间件传递参数
chain = middlewares.map(middleware => middleware(middlewareAPI))
// 4. 最终强化的 dispatch
dispatch = compose(chain)(store.dispatch)
return {
...store,
dispatch
}
}
}
middleWare
说明: 中间件的固定写法,如下是最经典的thunk的源码;
({ dispatch, getState }) => next => action => {
if (typeof action === 'function') return action(dispatch, getState)
// 直接的dispatch
return next(action);
}