一、redux使用

redux使用和之前的useReducer使用比较类似(详情请看 重学react——context/reducer 一文)

// store.ts
import { createStore, applyMiddleware, combineReducers } from 'redux';
import logger from 'redux-logger'; // 中间件
import thunk from 'redux-thunk'; // 中间件

export interface IState {
    name: string,
    age: number,
    sons: any[]
}

export const state: IState = {
    name: 'lihaixing',
    age: 32,
    sons: []
};

export type Action = {
    type?: string;
    data?: any;
};

export function reducer(state: IState | undefined, action: Action) {
    if (!action.type && !action.data) {
        return {
            ...state,
            ...action
        };
    }
    switch (action.type) {
        case 'update':
            return {
                ...state,
                ...action.data
            };
        default:
            return state;
    }
}


// createStore与useReducer类似
export const store = createStore(reducer, state, applyMiddleware(logger, thunk));
// contaner.tsx
import React, { useReducer } from 'react';

// react-redux的作用和react的context类似
import {Provider} from 'react-redux'; 
import { store } from './store';

import Com1 from './comp1'
import Com2 from './comp2'

const IndexView = () => {

    return <Provider store={store}>
        <Com1 />
        <Com2 />
    </Provider>
};

export default IndexView;
// com1.tsx
import React, { useContext } from 'react';
import { IState } from './index';
// connect和useContext的作用类似
import { connect } from 'react-redux';

const IndexView = (props: any) => {
    const {name, age, sons} = props.state;
    const {update, asyncUpdate} = props;
    const setAge = () => {
        // dispatch({type: 'update', data: {age: age + 1}});
        update({age: age + 1});
    };
    const setSons = () => {
        // setTimeout(()=>{
        //     update({sons: [...sons, 1]});
        // })

        asyncUpdate({sons: [...sons, 1]});

    };
    return <div>
        {name} <br/>
        {age} <br/>
        {sons} <br/>
        <button onClick={setAge}>按钮age</button>
        <button onClick={setSons}>按钮sons</button>
    </div>;
};

const mapStateToProps = (state: IState) => ({state});


const mapDispatchToProps = {
    update: (data: any) => ({type: 'update', data}),
    // 异步返回的是函数
    asyncUpdate: (data: any) => (dispatch: any) => {
        setTimeout(() => {
            dispatch({type: 'update', data});
        },1000);
    }
};

// 不传第二个参数,props会有dispatch
export default connect(mapStateToProps, mapDispatchToProps)(IndexView);

从上述我们可以将redux和useReducer/useContext作对比
重学react——context/reducer

二、手写Redux

1、createStore

export function createStore(reducer: any, state: any, enhancer?: any) {
    if (!!enhancer) {
        return enhancer(createStore)(reducer, state);
    }

    let currentState: any = state;
    const currentListener: any[] = [];

    function getState() {
        return currentState;
    }

    function dispatch(action: any) {
        currentState = reducer(currentState, action);
        currentListener.forEach((v) => v());
        return action;
    }

    function subscribe(cb: any) {
        currentListener.push(cb);
    }

    return {
        getState,
        dispatch,
        subscribe
    };
}

2、中间件

export function applyMiddleware(...middlewares: any) {
    return (createStore: any) => {
        return (reducer: any, state: any) => {
            const store = createStore(reducer, state);
            let dispatch = store.dispatch;
            const midApi = {
                getState: store.getState,
                dispatch: (...arg: any) => dispatch(...arg)
            };
            /**
             * 太难了,写不下去了
             * @type {any[]}
             */
            const chains = middlewares.map((mw: any) => mw(midApi));
            // 强化dispatch 按顺序执行
            dispatch = compose(...chains)(dispatch);
            console.log(dispatch)
            return {
                ...store,
                dispatch
            };
        };
    };
}

// 聚合函数 f3(f2(f1(arg)))
// const f1=(x)=>x;
// const f2=(x)=>2*x;
// const f3=(x)=>3*x;
export function compose(...funcs: any) {
    if (funcs.length === 1) {
        return funcs[0];
    }
    return funcs.reduce((left: any, right: any) => (...args: any) => right(left(...args)));
}
// 自己写一个中间件
function logger({getState, dispatch}: { getState: any, dispatch: any }) {
    return (dispatch: any) => (action: any) => {
        console.log(action.type + '执行了');
        return dispatch(action);
    };
}

function thunk({getState, dispatch}: { getState: any, dispatch: any }) {
    return (dispatch: any) => (action: any) => {
        if (typeof action === 'function') {
            return action(dispatch, getState);
        }
        return dispatch(action);
    };
}

系列

重学react——slot
重学react——state和生命周期
重学react——redux
重学react——hooks以及原理
重学react——context/reducer
重学react——router
重学react——高阶组件
build your own react
React——fiber


lihaixing
463 声望719 粉丝

前端就爱瞎折腾