• 手写一个Redux,深入理解其原理-面试进阶


    Redux可是一个大名鼎鼎的库,很多地方都在用,我也用了几年了,今天这篇文章就是自己来实现一个Redux,以便于深入理解他的原理。我们还是老套路,从基本的用法入手,然后自己实现一个Redux来替代源码的NPM包,但是功能保持不变。本文只会实现Redux的核心库,跟其他库的配合使用,比如React-Redux准备后面单独写一篇文章来讲。有时候我们过于关注使用,只记住了各种使用方式,反而忽略了他们的核心原理,但是如果我们想真正的提高技术,最好还是一个一个搞清楚,比如Redux和React-Redux看起来很像,但是他们的核心理念和关注点是不同的,Redux其实只是一个单纯状态管理库,没有任何界面相关的东西,React-Redux关注的是怎么将Redux跟React结合起来,用到了一些React的API。

    基本概念

    Redux的概念有很多文章都讲过,想必大家都看过很多了,我这里不再展开,只是简单提一下。Redux基本概念主要有以下几个:

    Store

    人如其名,Store就是一个仓库,它存储了所有的状态(State),还提供了一些操作他的API,我们后续的操作其实都是在操作这个仓库。假如我们的仓库是用来放牛奶的,初始情况下,我们的仓库里面一箱牛奶都没有,那Store的状态(State)就是:

    {
        milk: 0
    }
    
    • 1
    • 2
    • 3

    Actions

    一个Action就是一个动作,这个动作的目的是更改Store中的某个状态,Store还是上面的那个仓库,现在我想往仓库放一箱牛奶,那"我想往仓库放一箱牛奶"就是一个Action,代码就是这样:

    {
       
      type: "PUT_MILK",
      count: 1
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Reducers

    前面"我想往仓库放一箱牛奶"只是想了,还没操作,具体操作要靠Reducer,Reducer就是根据接收的Action来改变Store中的状态,比如我接收了一个PUT_MILK,同时数量count是1,那放进去的结果就是milk增加了1,从0变成了1,代码就是这样:

    const initState = {
       
      milk: 0
    }
    
    function reducer(state = initState, action) {
       
      switch (action.type) {
       
        case 'PUT_MILK':
          return {
       ...state, milk: state.milk + action.count}
        default:
          return state
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    参考 前端react面试题详细解答

    可以看到Redux本身就是一个单纯的状态机,Store存放了所有的状态,Action是一个改变状态的通知,Reducer接收到通知就更改Store中对应的状态。

    简单例子

    下面我们来看一个简单的例子,包含了前面提到的Store,Action和Reducer这几个概念:

    import {
        createStore } from 'redux';
    
    const initState = {
       
      milk: 0
    };
    
    function reducer(state = initState, action) {
       
      switch (action.type) {
       
        case 'PUT_MILK':
          return {
       ...state, milk: state.milk + action.count};
        case 'TAKE_MILK':
          return {
       ...state, milk: state.milk - action.count};
        default:
          return state;
      }
    }
    
    let store = createStore(reducer);
    
    // subscribe其实就是订阅store的变化,一旦store发生了变化,传入的回调函数就会被调用
    // 如果是结合页面更新,更新的操作就是在这里执行
    store.subscribe(() => console.log(store.getState()));
    
    // 将action发出去要用dispatch
    store.dispatch({
        type: 'PUT_MILK' });    // milk: 1
    store.dispatch({
        type: 'PUT_MILK' });    // milk: 2
    store.dispatch({
        type: 'TAKE_MILK' });   // milk: 1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    自己实现

    前面我们那个例子虽然短小,但是已经包含了Redux的核心功能了,所以我们手写的第一个目标就是替换这个例子中的Redux。要替换这个Redux,我们得先知道他里面都有什么东西,仔细一看,我们好像只用到了他的一个API:

    createStore:这个API接受reducer方法作为参数,返回一个store,主要功能都在这个store上。

    看看store上我们都用到了啥:

    store.subscribe: 订阅state的变化,当state变化的时候执行回调,可以有多个subscribe,里面的回调会依次执行。

    store.dispatch: 发出action的方法,每次dispatch action都会执行reducer生成新的state,然后执行subscribe注册的回调。

    store.getState:一个简单的方法,返回当前的state

    看到subscribe注册回调,dispatch触发回调,想到了什么,这不就是发布订阅模式吗?

    function createStore() {
       
      let state;              // state记录所有状态
      let listeners = [];     // 保存所有注册的回调
    
      function subscribe(callback) {
       
        listeners.push(callback);       // subscribe就是将回调保存下来
      }
    
      // dispatch就是将所有的回调拿出来依次执行就行
      function dispatch() {
       
        for (let i = 0; i < listeners.length; i++) {
       
          const listener = listeners[i];
          listener();
        }
      
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
  • 相关阅读:
    【PCBA方案】快速测温体温计方案
    【Linux】提升Linux命令行效率:光标移动和文本操作的键盘快捷键
    整治PPOCRLabel中cv2文件读取问题(更新中)
    [GKCTF 2021]Crash
    【grafana | clickhouse】实现展示多折线图
    matlab小车运动轨迹增量式PID控制
    ZooKeeper调优
    飞天使-学以致用-devops知识点4-SpringBoot项目CICD实现(实验失败,了解大概流程)
    NodeJS 5分钟 连接 Redis 读写操作
    【CoderSay】Code For Better 谷歌开发者之声 - 相遇2022GoogleSummit
  • 原文地址:https://blog.csdn.net/beifeng11996/article/details/127763137