拆解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

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

相关推荐
不在逃避q31 分钟前
Trae/Vs Code/Cursor命令行无法跑npm命令
前端·arcgis·npm
夏殇之殁1 小时前
包中创建自定义列表项。 . 使用自定义列表项进行数据绑定 . 将天气预报数据保存到本地内存表,通过LiveBindings进行显示。 ...
服务器·前端·javascript
The Chosen One9851 小时前
高进度算法模板速记(待完善)
java·前端·算法
陈随易1 小时前
MoonBit抓包模块pcap,查看电脑的每一次联网通信
前端·后端·程序员
新中地GIS开发老师2 小时前
WebGIS开发学生作品|低空航天管理与航线规划系统
前端·javascript·webgis·三维gis开发
用户059540174462 小时前
大模型对话记忆持久化踩坑实录:用 Playwright 自动化测了 300 次,终于揪出会话丢失的真凶
前端·css
丙氨酸長鏈2 小时前
Web前端入门第 问:JavaScript 一个简单的 IndexedDB 数据库入门示例
前端·javascript·数据库
kyriewen3 小时前
面试官让我手写虚拟列表——AI生成的版本,快速滚动几下就白屏了
前端·javascript·面试
IT_陈寒4 小时前
Vite热更新失效?你可能漏了这个配置
前端·人工智能·后端
梅孔立4 小时前
两种免费的翻译API调用方式详解 - Edge官方API与个人缓存服务
前端·缓存·edge