深入理解Redux:简单实现一个Redux以及React-Redux

前言

redux相信都不陌生(陌生的看中文文档:https://www.redux.org.cn/),它是 JavaScript 状态容器,提供可预测化的状态管理,你可以在React, Vue, Angular,服务端等地方使用。redux由三部分组成:Action, Reducer, Store,你需要编写的是Action和Reducer,比如最简单的计数器例子

Action 部分

// action type
const INCREMENT = "increment";
const DECREMENT = "decrement";

// action creator 也叫action 创建函数
function increment() {
    return {
        type: INCREMENT
    }
}

function decrement() {
    return {
        type: DECREMENT
    }
}

Reducer 部分

const initialState = {
    count: 0
};

function countReducer(state = initialState, action) {
    switch (action.type) {
        case INCREMENT: {
            return {
                count: state.count + 1
            }
        }
        case DECREMENT: {
            return {
                count: state.count - 1
            }
        }
        default: {
            return state
        }
    }
}

Store 部分

const store = createStore(countReducer);

// 设置监听
store.subscribe(() => {
    console.log(store.getState().count);
});
// 设置时间间隔去触发动作
setInterval(() => {
    store.dispatch(increment());
}, 1000);

一个简单的redux应用就由上面三部分组成,重点关注createStore方法,因为算是它结合了Action和Reducer,而且也算是redux的核心,所以我们尝试编写一个简单的createStore函数

Redux的createStore的简单实现

redux的createStore函数接收reducer,initialState两个参数,(middleware暂时先不考虑),然后返回一个对象,如下所示

{
   getState () {},
   dispatch (action) {},
   subscribe (newListener) {},
   replaceReducer (newReducer) {}
}

 所以我们很容易的就编写了以下createStore的简单实现代码

JavaScript

function createStore (reducer, initialState = reducer(void 0, { type: null })) {
    let state = initialState; // 存储state
    let currentReducer = reducer; // 存储当前的reducer
    let listener = []; // 存储监听函数

    return {
        getState () {
            return state
        },
        dispatch (action) {
            state = currentReducer(state, action); // reducer用在这了
            listener.forEach(cb => cb()); // 核心,每次调用dispatch时都调用监听的函数
            return action;
        },
        subscribe (newListener) {
            listener.push(newListener);
        },
        replaceReducer (newReducer) {
            currentReducer = newReducer
        }
    }
}

typescript版

export type Action = {
    type: string,
    [props: string]: any
};
export type ReducerType = (state: any, action: Action) => any;
export type Dispatch = (action: T) => any;
export type Store = {
    getState: () => T,
    dispatch: Dispatch,
    subscribe: (listener: Function) => void,
    replaceReducer: (reducer: ReducerType) => void
};

export function createStore (reducer: ReducerType, initialState = reducer(void 0, { type: "" })): Store {
    let state = initialState;
    let currentReducer = reducer;
    let listener: Array = [];

    return {
        getState () {
            return state
        },
        dispatch (action: Action) {
            state = currentReducer(state, action);
            listener.forEach(cb => cb());
            return action;
        },
        subscribe (newListener: Function) {
            listener.push(newListener);
        },
        replaceReducer (newReducer: ReducerType) {
            currentReducer = newReducer
        }
    }
}

好了,一个简易的createStore就完成了,当然跟redux的createStore还是有一定差别的,比如没有中间件(这个后期在实现吧),没有异常处理等等

React-Redux的Provider实现

在react中,一般会使用React-Redux库,而最常用的就是组件和conncet方法了,接下了将简单实现Provider组件和conncet方法

基于typescript

import React from "react";
import { Store, Dispatch, Action } from "./createStore";

export interface ProviderProps {
    store: Store
}

const StoreContext = React.createContext({
    store: {}
});

// Provider组件实现,主要使用react 的Context
export class Provider extends React.Component {

    constructor (props: any) {
        super(props);
    }

    render (): React.ReactNode {
        let value = {
            store: this.props.store
        };
        // 利用Context 将store传到子组件中
        return (
            
                { this.props.children }
            
        )
    }
}

type mapStateType = (state: any) => any;
type mapDispatchType = (dispatch: (action: any) => any) => any;
// connect函数,其实就是高阶组件,利用了属性代理
export const connect = (mapStateToProps: mapStateType, mapDispatchToProps: mapDispatchType) =>
    (Component: React.ElementType) =>
        class NewComponent extends React.Component {
            state = {};
            static contextType = StoreContext; // !!!

            constructor (props: any, context: any) {
                super(props);
            }

            componentDidMount (): void {
                let store = this.context.store as Store; // 从context中获取store
                store.subscribe(this.update); // 主要是设置监听器,当组件状态更新,将反应回store,使store也更新
                this.update();
            }

            private update = () => {
                let store = this.context.store as Store;
                let state = store.getState();
                const filterState = mapStateToProps(state); // !!
                const actions = mapDispatchToProps(store.dispatch); // !!
                this.setState({ ...filterState, ...actions });
            };

            render (): React.ReactNode {
                return 
            }
        };

结合我们实现的createStore以及Provider组件,connect函数,我们来实现一个计数器的小例子

代码如下:

typescript

import React from 'react';
import ReactDOM from 'react-dom';
import "./index.css";
import { createStore, Action, Dispatch, Store } from "./createStore";
import { Provider, connect } from "./Provider";

// Action
const INCREMENT = "increment";
const DECREMENT = "decrement";

function increment (): Action {
    return {
        type: INCREMENT
    }
}

function decrement (): Action {
    return {
        type: DECREMENT
    }
}

// Reducer
type StoreState = {
    value: number
};

function reducer (state: StoreState = { value: 0 }, action: Action) {
    switch (action.type) {
        case INCREMENT: {
            return {
                value: state.value + 1
            }
        }
        case DECREMENT: {
            return {
                value: state.value - 1
            }
        }
        default: {
            return state
        }
    }
}

// Store
let CountStore = createStore(reducer);


type CountProps = {
    count: number;
    onDecrement: () => void;
    onIncrement: () => void;
};

function Count (props: CountProps) {
    return (
        
{ props.count }
) } const mapStateToProps = (state: any) => ({ count: state.value }); const mapDispatchToProps = (dispatch: Dispatch) => ({ onDecrement: () => dispatch(decrement()), onIncrement: () => dispatch(increment()) }); const CountContainer: React.ElementType = connect(mapStateToProps, mapDispatchToProps)(Count); type MyAppProps = { store: Store }; class MyApp extends React.Component { constructor (props: MyAppProps) { super(props); } render () { return ( ); } } const render = () => ReactDOM.render( , document.getElementById('root') as HTMLElement ); CountStore.subscribe(render); render();

可以在浏览器上看效果

深入理解Redux:简单实现一个Redux以及React-Redux_第1张图片

总结

通过简单实现redux的createStore,以及react-redux的Provider, connect,能对redux的架构更加熟悉,知其所以然,所以用才会顺心顺手,当然上面只是一个简单的实现,如果要用于开发的话,当然建议直接用redux和react-redux,最后:由于代码是用typescript写的,所以转成JavaScript的话将类型定义给去了就好了(或者参考这里,创建一个typescript的React的项目: https://facebook.github.io/create-react-app/docs/adding-typescript),不得不说,用typescript写react真特么爽  d=====( ̄▽ ̄*)b

参考链接

https://www.jb51.net/article/146409.htm

https://www.jianshu.com/p/b766aaa8217c

你可能感兴趣的:(javascript,React,Redux,typescript)