实现一个简单的redux

2019-07-01 11:23:28 浏览数 (1)

刚开始接触到redux的时候, 对于redux中的概念, 只有一个store是知道的, 其他的都像是在阅读天书一样. 网上找了很多资料和文档来阅读, 也是通过多次的实践,慢慢的对于redux的概念一知半解, 想着如此就去阅读一下源码, 或许会有不一样的收获.于是就有了这篇文章

关于redux,

只需要记住它是一个状态管理器, 于react无关, 是一个独立的库 state: 表示状态 dispatch: 改变状态 reducer: 包含改变状态的数据 subscribe: 订阅state 中间件

我们来看看redux的核心是怎么改变数据的:

代码语言:txt复制
let state = { name: 'liang' };
state.name = 'Tim';

这样是不是就实现了数据的改变了呢?!

估计这样会被读者打死o(╥﹏╥)o , 但是redux的核心就是这样的, 我们一步步展开来说。

上面的代码虽然实现了修改, 但是却没有通知到所有使用到name的地方上,我们通过发布订阅来实践一下

代码语言:txt复制
let state = { name: 'liang' };
let listeners = [];
function subscribe(listener) {
  listeners.push(listener);
};
function changeState(name) {
  state.name = name;
  for (let i = 0; i < listeners.length; i  ) {
    const listener = listeners[i];
    listener();
  }
}

/*-------我是分割线--------*/
//订阅state中的数据
subscribe(() => {
  console.log(state.name);
});

changeState('小米'); //小米 
changeState('小红'); //小红

上面的例子确实通过发布订阅实现了数据的改变时,通知到每个监听的地方,但是却有几个问题:

  • 只能改变name,不通用
  • 公共的代码应该封装起来

于是,我们尝试着将代码封装起来,形成一个可通用的代码。

代码语言:txt复制
function createState(initState) {
  let state = initState;
  let listeners = [];
  //订阅功能
  function subscribe(listener) {
    listeners.push(listener);
  }
  //改变状态的方法同时通知所有的订阅者
  function changeState(newState) {
    state = newState;
    for(let i = 0; i < listeners.length; i  ) {
      const listener = listeners[i];
      listener();
    }
  }
  //获取状态
  function getState() {
    return state;
  }
  return { getState, changeState, subscribe };
}

我们使用上面的代码来试一下效果

代码语言:txt复制
let initState = {
  count: 1,
  person: {
    name: '小红',
    sex: '女'
  },
};
const store = createState(initState);
store.subscribe(() => {
  let state = store.getState();
  console.log(`名字:${state.person.name},性别:${state.person.sex}`);
});
store.subscribe(() => {
  let state = store.getState();
  console.log(state.count);
});
store.changeState({ ...store.getState(), count: 2 });
//名字:小红,性别:女
//2
store.changeState({ ...store.getState(), person: { name: '小明', sex: '男' } });
//名字:小明,性别:男
//2

这样我们就实现了一个简单的状态管理器了。

这时候是不是应该不要脸的鼓励自己,完成了redux的核心☺,但是这个仅仅只是个开始,我们目标当然是完成一个完整redux了,尽管不能媲美真正的redux(毕竟人家已经是老牌选手了),但是我们不能放弃造轮子的梦想。于是,我们重新来看这段代码,假设我们修改如下

代码语言:txt复制
store.changeState({ ...store.getState(), count: 'abc' });
//名字:小明,性别:男
//abc

从结果来看,count的类型发生了改变,它可以被任意的修改,我们需要约束一下,更希望能够有计划的去改变,而上面的代码不能够支持这种能力,于是,我们扩展开来:

  • 希望有个函数可以控制值的返回,我们叫它为handle吧
  • 让store.changeState方法知道,告诉它修改state的时候,按我们的希望的修改

我们来实现handle函数,它接受一个老的state和一个包含改变state的对象,返回新的state

代码语言:txt复制
function handle(state, action) {
  switch(action.type) {
    case 'INCREMENT':
      return { ...state, count: state.count   1 };
    case 'DECREMENT':
      return { ...state, count: state.count - 1 };
    default:
      return state;
  }
}

在我们的createState函数中增加handle函数

代码语言:txt复制
function createState(handle, initState) {
  let state = initState;
  let listeners = [];
  //订阅功能
  function subscribe(listener) {
    listeners.push(listener);
  }
  //通知
  function changeState(action) {
    //按我们期望的返回
    state = handle(state, action);
    for(let i = 0; i < listeners.length; i  ) {
      const listener = listeners[i];
      listener();
    }
  }
  function getState() {
    return state;
  }
  return { getState, subscribe, changeState };
}

我们来尝试一下:

代码语言:txt复制
let initState = { count: 0 };
const store = createState(handle, initState);
store.subscribe(() => {
  console.log(store.getState().count);
});
store.changeState({ type: 'INCREMENT' }); //1
store.changeState({ type: 'DECREMENT' }); //0
store.changeState({ count: 'abc' }); //0

从结果来看,我们已经实现了我们的功能了,state可以按照我们期望的要求进行改变了,对count直接进行改变已经是没有效果了的。

到此为止,我们已经实现一个完整的状态管理器。这也是redux的核心之一。

现在,我们来商量一下,我们把名字改一下,把changeState改成dispatch,handle改成reducer,这样是不是感觉很厉害,很高大上的样子☺!!!毕竟reudx就是这样叫的,我们当然要向它学习了。

总结

  1. 利用发布订阅模式实现通知每个监听的地方
  2. 通过handle函数实现了有计划的控制返回的数据

redux肯定远远不止这些,如果想知道更多,请留意下回分解

详情传送门 : https://github.com/reduxjs/redux/tree/master/src

0 人点赞