摸鱼实在太无聊,自己写了一个Redux!

1,142 阅读2分钟

参考了网上很多大佬写的,这里先上链接,阮一峰老师的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 };

第一次写文章,希望大佬们多多指教!!!!后续会进行修改。