拆解Redux:从零手写一个状态管理器,彻底搞懂它的魔法!

大家好,我是小杨,一个在前端领域摸爬滚打了6年的"老油条"。今天想和大家聊聊Redux------这个曾经让我又爱又恨的状态管理库。很多新手觉得它复杂,但其实它的核心思想非常简单。为了彻底搞懂它,我决定带大家从零手写一个迷你Redux!

1. 为什么我需要Redux?一个血泪故事

还记得我刚接触复杂前端项目时,组件的状态传递像一团乱麻:

  • parentComponent 要传数据给 nestedChildComponent,得经过3层中间组件。
  • 兄弟组件之间修改状态?只能用回调地狱或者事件总线,代码难以维护。

直到我遇到了Redux,它的单一数据源单向数据流 像一束光拯救了我。但光会用不够,理解原理才能避免踩坑

2. Redux的三大核心:Store、Action、Reducer

先看官方定义?不,我用一个计数器例子解释:

javascript 复制代码
// 1. 定义Reducer(纯函数!)
function counterReducer(state = 0, action) {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1;
    case 'DECREMENT':
      return state - 1;
    default:
      return state;
  }
}

// 2. 创建Store(Redux.createStore的秘密)
const store = myCreateStore(counterReducer);

// 3. 触发Action(为什么必须用dispatch?)
store.dispatch({ type: 'INCREMENT' });
console.log(store.getState()); // 输出:1

关键点:

  • Reducer必须是纯函数,不能直接修改state!
  • Action是一个普通对象,但必须有type字段。
  • Store通过dispatch管理状态变更,避免随意修改。

3. 手写myCreateStore:20行代码揭示核心原理

Redux的魔法就藏在createStore里!下面是我的实现:

javascript 复制代码
function myCreateStore(reducer) {
  let currentState;
  const listeners = [];

  function getState() {
    return currentState;
  }

  function dispatch(action) {
    currentState = reducer(currentState, action);
    listeners.forEach(listener => listener()); // 通知所有订阅者
  }

  function subscribe(listener) {
    listeners.push(listener);
    return () => {
      const index = listeners.indexOf(listener);
      listeners.splice(index, 1);
    };
  }

  dispatch({ type: '@@INIT' }); // 初始化state
  return { getState, dispatch, subscribe };
}

为什么这样设计?

  • listeners 数组实现观察者模式,状态变化时自动更新UI(比如React的connect)。
  • 初始dispatch确保Reducer返回默认state。

4. 实战踩坑:我曾经犯过的3个错误

❌ 直接修改state

javascript 复制代码
// 错误写法!
function wrongReducer(state = { count: 0 }, action) {
  state.count += 1; // 直接修改了原state!
  return state;
}

后果: React组件不会重新渲染,因为浅比较发现引用未变。

❌ 在Reducer里执行异步操作

javascript 复制代码
// 错误示例!
function asyncReducer(state, action) {
  fetch('/api').then(() => { // 副作用!
    return { ...state, data: action.payload };
  });
}

正确做法: 用中间件(如redux-thunk)处理异步。

❌ 滥用Store存储局部状态

教训: 表单的临时输入值应该用组件state,而非全局Store。

5. 进阶:中间件(Middleware)机制揭秘

Redux最强大的特性是中间件。比如实现一个logger:

javascript 复制代码
function loggerMiddleware(store) {
  return function(next) {
    return function(action) {
      console.log('dispatching:', action);
      const result = next(action);
      console.log('next state:', store.getState());
      return result;
    };
  };
}

洋葱模型: 中间件的嵌套执行流程是Redux的灵魂。

6. 总结:Redux的设计哲学

  • 单向数据流:状态变化可预测。
  • 函数式编程:Reducer是纯函数,易于测试。
  • 发布订阅:高效管理状态依赖。

我的建议: 即使现在用Redux Toolkit或Zustand,理解Redux原理依然能让你更好地驾驭状态管理。

⭐ 写在最后

请大家不吝赐教,在下方评论或者私信我,十分感谢🙏🙏🙏.

✅ 认为我某个部分的设计过于繁琐,有更加简单或者更高逼格的封装方式

✅ 认为我部分代码过于老旧,可以提供新的API或最新语法

✅ 对于文章中部分内容不理解

✅ 解答我文章中一些疑问

✅ 认为某些交互,功能需要优化,发现BUG

✅ 想要添加新功能,对于整体的设计,外观有更好的建议

✅ 一起探讨技术加qq交流群:906392632

最后感谢各位的耐心观看,既然都到这了,点个 👍赞再走吧!

相关推荐
崔璨几秒前
详解Vue3的响应式系统
前端·vue.js
摸鱼的鱼lv几秒前
🔥 Vue.js组件通信全攻略:从父子传值到全局状态管理,一篇搞定所有场景!🚀
前端·vue.js
IT_陈寒12 分钟前
Java性能优化:10个让你的Spring Boot应用提速300%的隐藏技巧
前端·人工智能·后端
whysqwhw30 分钟前
Hippy 跨平台框架扩展原生自定义组件的完整实现方案对比
前端
dasseinzumtode1 小时前
nestJS 使用ExcelJS 实现数据的excel导出功能
前端·后端·node.js
子兮曰1 小时前
🔥C盘告急!WSL磁盘暴增?三招秒清20GB+空间
前端·windows·docker
Jinuss1 小时前
Vue3源码reactivity响应式篇之EffectScope
前端·vue3
stoneship1 小时前
网页截图API-Npm工具包分享
前端
Jedi Hongbin1 小时前
Three.js shader内置矩阵注入
前端·javascript·three.js
etcix1 小时前
dmenux.c: integrate dmenu project as one file
c语言·前端·算法