手动实现简易版redux

手动实现简易版redux

源码地址:kredux分支

先来回顾下redux工作方式

  • store 状态管理容器,内置getState, dispatch, subscribe方法
  • state 改变的唯一方式是通过 store.dispatch(action) 来触发reducer,reducer根据action传来的type实现不同的更新state措施
  • 由于redux无法异步,所以需要对redux进行扩展,当然不仅针对异步,也可以根据个人需求对dispatch过程进行“订制”。

基于此,要手写一个redux, 首先要实现下面方法

  • action
  • reducer
  • createStore(reducer, enhaner) { reutrn (getState, dispatch, subscribe)}

要对redux进行扩展,需要使用中间件,要完成下面方法:

  • applyMiddleware 对原store的dispatch方法进行扩展
  • compose 如果接收的扩展方法有多个,则对扩展数组内容逐个扩展 如[a,b],最终实现 a(b(dispatch))
  • 扩展方法,如logger/thunk 对dispatch进行拦截,并返回新的dispatch或action

接下来,正文开始

action 页面调用

// src/page/ReduxPage.js
export default class reduxPage extends Component {
  componentDidMount(){
  	store.subscribe(()=>{
    	this.forceUpdate()
    })
  }
  // action 方法实现
  add = () => {
  	store.dispatch({type: "ADD"})
  };
	return (
  	<div>
     	...
     </div>
  )
}

reducer 方法

// src/store/index.js

// reducer 实现
function countReducers(state=0, action){
	switch(action.type):
    case "ADD":
    	return state + 1;
    case "MINU":
    	return state - 1;
    default:
    	return state
}
  
// store 创建
const store = createStore(countReducer, applyMiddleware(thunk, logger));

实现 createStore

function createStore(reducer, enhaner){
  // 有扩展就执行扩展
  if (enhancer) {
    return enhancer(createStore)(reducer);
  }
  let currentState = undefined;
  let currentListeners = [];
  
  function getState() {
    return currentState;
  }
  
  function dispatch(action) {
    currentState = reducer(currentState, action);
    // 监听函数是一个数组,那就循环吧
    currentListeners.map(listener => listener());
  }

  //订阅,可以多次订阅
  function subscribe(listener) {
    // 每次订阅,把回调放入回调数组
    currentListeners.push(listener);
  }

  // 取值的时候,注意一定要保证不和项目中的会重复
  dispatch({type: "@INIT/REDUX-KKB"});

  return {
    getState,
    dispatch,
    subscribe
  };
}

进行扩展

applyMiddleware 中间件

// src/kRedux.js
// applyMiddleware(thunk, logger)
export function applyMiddleware(...middlewares) {
  return createStore => (...args) => {
    // 第一部分 要对原store扩展,先取到原store API
    const store = createStore(...args);
    let dispatch = store.dispatch;
    const middleApi = {
      getState: store.getState,
      dispatch
    };
    
    // 给middleware参数,比如说dispatch, map方法得到的是个全新数组
    const middlewaresChain = middlewares.map(middleware =>
      middleware(middleApi)
    );
    
    dispatch = compose(...middlewaresChain)(dispatch);
    
    return {
      ...store,
      // 覆盖上面store里的dispatch
      dispatch
    };
  };
}


function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg;
  }
  if (funcs.length === 1) {
    return funcs[0];
  }
  
  // 多个扩展时,依次调用[thunk, logger]
  return funcs.reduce((a, b) => (...args) => a(b(...args)));
}

扩展方法

// src/store/index.js

// 日志扩展
function logger({getState, dispatch}) {
  return dispatch => action => {
    console.log(action.type + "执行了");
    return dispatch(action);
  };
}

// 异步扩展
function thunk({getState, dispatch}) {
  return dispatch => action => {
    // action 可以是对象 还可以是函数 ,那不同的形式,操作也不同
    if (typeof action === "function") {
      return action(dispatch, getState);
    } else {
      return dispatch(action);
    }
  };
}
发布了171 篇原创文章 · 获赞 246 · 访问量 24万+

猜你喜欢

转载自blog.csdn.net/weixin_42042680/article/details/104470546