参考了网上很多大佬写的,这里先上链接,阮一峰老师的redux入门教程。
第一次写文章,望大佬们多多指教。
www.ruanyifeng.com/blog/2016/0…
createStore
let currentState = initState;const listener = [];
我的理解是createStore创建了一个闭包,里面定义了整个项目的state; 通过抛出getState方法来让外界能获取到当前state,通过抛出dispatch来让外界生成新的state; 通过抛出subscribe方法来让外界可以订阅state的改变,从而触发组件render或者其他操作。
currentState 存储的就是当前应用的状态,listener里面保存外界对currentState改变所产生的影响,每当外界通过dispatch生成了新的currentState, 就会遍历listener,执行所有的订阅方法。这里因为我参考了dva里的model定义方式,所以dispatch方法不太一样,具体的定义方法后续会有。
完整代码如下
const createStore = (initState, reducer) => { let currentState = initState; const listener = []; const getState = () => currentState; const dispatch = ({ type, payload }) => { const name = type.split('/'); if (name.length === 2 && reducer[name[0]] && reducer[name[0]][name[1]]) { currentState = { ...currentState, [name[0]]: reducer[name[0]][name[1]](currentState[name[0]], payload) } listener.forEach(sub => { sub && typeof sub === 'function' && sub(); }); } } const subscribe = (sub) => { listener.push(sub); return () => { let index = listener.findIndex((s) => s === sub); if (index !== -1) { listener.splice(index, 1); } } } return { getState, dispatch, subscribe }}
combineReducers
const dataReducer = { namespace: 'dataList', state: { list: [] }, reducer: { saveList(state, payload) { return {...state, list: payload}; } }}
reducer的定义方法,参考了dva里的model定义方法,除了effects。
const combineReducers = (reducers = []) => { if (reducers instanceof Array === false) { console.error('组合reducer失败, 请检查传入参数是否为reducer数组'); return; } const result = reducers.reduce((x, y) => { if(Object.keys(x.state).findIndex(item => item === y.namespace) !== -1) { console.error('reducer命名冲突, 会覆盖!') } return { state: {...x.state, [y.namespace]: y.state}, reducer: { ...x.reducer, [y.namespace]: y.reducer } } }, {state: {}, reducer: {}}); return result;}
combineReducers该函数是我用来组装多个reducer,其实就是把每个reducer里的state,reducer合并。
如何使用
上面介绍了2个主要的方法,下面就是如何生成store,并注入到项目中。
通过react提供的context上下文,把createStore生成的唯一store注入到组件顶层,后续通过hook里的useContext来取出store.
这里我试着写了个hook版本的useConnect,该函数和dva里的connect使用差不多,就是提取你所需要用到的store中存储的state,在里面订阅了state的更新,每当state更新就会触发setState,进而触发组件的渲染。
import React, { createContext, useContext, useEffect, useState } from 'react';import { countReducer, dataReducer } from './reducers';import { createStore, combineReducers } from './store';const { state, reducer } = combineReducers([countReducer, dataReducer]);const store = createStore(state, reducer);const Context = createContext();const useConnect = (mapStateToProps) => { const _store = useContext(Context); const [state, setState] = useState({}); useEffect(() => { const _state = mapStateToProps(_store.getState()); setState({ ..._state }); const fn = _store.subscribe(() => { const _state = mapStateToProps(_store.getState()); setState({ ..._state }); // 这里可以优化掉不必须要的渲染 }); return fn; }, []); return [ state, _store.dispatch ];}const provider = (Component) => { return () => <Context.Provider value={store}> <Component /> </Context.Provider>}export { useConnect, provider };
第一次写文章,希望大佬们多多指教!!!!后续会进行修改。