手写迷你React:300行代码带你彻底理解React核心原理

手写迷你React:300行代码带你彻底理解React核心原理 从“魔法”到代码React 到底是什么很多开发者说 React 就像“黑魔法”你写声明式代码React 自动高效更新 UI。但这背后真的有那么神秘吗React 的核心其实就是三个基本概念虚拟 DOM - UI 的描述协调算法 - 找到最小更新路径声明式 API - 你描述“想要什么”而不是“怎么做到”今天阿浪不只讲概念而要亲手实现一个 300 行的迷你 React从代码层面彻底理解 React 的工作原理。为什么亲手实现比读源码更有效阅读 React 源码就像观察一台复杂机器的运行而亲手实现则是拆解并重新组装它的核心部件。只有亲手构建你才能真正理解为什么 React 选择虚拟 DOM 而不是直接操作 DOM协调算法如何决定哪些部分需要更新Hooks 的设计哲学和限制从何而来第 1 部分虚拟 DOM - 比你想的简单很多人把虚拟 DOM 想得太复杂其实它只是一个普通的 JavaScript 对象// 这就是虚拟DOM的全部秘密constvirtualNode{type:div,// 标签名或组件类型props:{// 所有属性和子节点className:container,onClick:()console.log(点击了),children:[// 子节点数组{type:h1,props:{children:Hello React}}]}}虚拟 DOM 的关键价值​抽象平台差异​同一套虚拟 DOM 可渲染到 Web、Native、VR 等不同平台​计算最小更新​通过比较找出最少的 DOM 操作​声明式编程模型​你只需描述 UI 状态React 负责同步到真实 UI让我们实现创建虚拟 DOM 的函数functioncreateElement(type,props,...children){return{type,props:{...props,// 统一处理子节点文本节点特殊处理children:children.map(childtypeofchildobject?child// 已经是虚拟DOM节点:createTextElement(child)// 文本转换为虚拟DOM)}};}functioncreateTextElement(text){return{type:TEXT_ELEMENT,props:{nodeValue:text,children:[]// 文本节点没有子节点}};}第 2 部分渲染 - 从虚拟到真实有了虚拟 DOM我们需要把它变成真实的 DOM 并显示出来functionrender(element,container){// 创建DOM元素constdomelement.typeTEXT_ELEMENT?document.createTextNode()// 文本节点:document.createElement(element.type);// 元素节点// 设置属性Object.keys(element.props).filter(keykey!children)// children单独处理.forEach(name{// 处理事件以on开头的属性if(name.startsWith(on)){consteventTypename.toLowerCase().substring(2);dom.addEventListener(eventType,element.props[name]);}else{// 设置普通属性dom[name]element.props[name];}});// 递归渲染子节点element.props.children.forEach(child{render(child,dom);});// 添加到容器container.appendChild(dom);}到这里我们已经实现了一个最简单的React它可以创建和渲染静态 UI。但真正的 React 核心在于​更新​而不是初次渲染。第 3 部分协调算法 - React 的智能比较引擎这是 React 最精髓的部分。想象你要在两个 DOM 树之间找出差异最笨的方法是全部重新创建但 React 的协调算法要聪明得多。// 核心协调函数functionreconcile(parentNode,oldNode,newNode,index0){// 情况1新增节点if(!oldNodenewNode){constdomcreateDom(newNode);parentNode.appendChild(dom);returndom;}// 情况2删除节点if(oldNode!newNode){parentNode.removeChild(parentNode.childNodes[index]);returnnull;}// 情况3节点类型不同 → 完全替换if(oldNode.type!newNode.type){constdomcreateDom(newNode);parentNode.replaceChild(dom,parentNode.childNodes[index]);returndom;}// 情况4节点类型相同 → 更新属性递归比较子节点constdomparentNode.childNodes[index];updateDom(dom,oldNode.props,newNode.props);// 递归比较子节点reconcileChildren(dom,oldNode.props.children,newNode.props.children);returndom;}​这就是 React 性能的关键​当节点类型相同时React 会尽可能复用现有 DOM 节点只更新变化的属性。这比销毁再创建要高效得多。第 4 部分Hooks 原理 - 为什么有那些奇怪规则React Hooks 看似神奇但原理其实很直接lethookIndex0;// 当前hook的索引lethooks[];// 存储所有hook的状态functionuseState(initialValue){constindexhookIndex;// 保存当前hook的位置// 首次渲染时初始化状态if(hooks[index]undefined){hooks[index]initialValue;}// 获取当前状态conststatehooks[index];// 创建setState函数constsetState(newValue){hooks[index]newValue;// 更新状态rerender();// 触发重新渲染};hookIndex;// 移动到下一个hook的位置return[state,setState];}现在你明白 Hooks 的规则从何而来了​必须按顺序调用​因为 React 靠调用顺序来跟踪状态​不能在条件语句中使用​这会打乱 hook 的调用顺序​只能在函数组件顶层调用​确保每次渲染的 hook 顺序一致完整实现300 行迷你 React// mini-react.jslethookIndex0;lethooks[];letcurrentComponentnull;letcurrentContainernull;functioncreateElement(type,props,...children){return{type,props:{...props,children:children.map(childtypeofchildobject?child:createTextElement(child))}};}functioncreateTextElement(text){return{type:TEXT_ELEMENT,props:{nodeValue:text,children:[]}};}functioncreateDom(element){constdomelement.typeTEXT_ELEMENT?document.createTextNode():document.createElement(element.type);updateDom(dom,{},element.props);returndom;}functionupdateDom(dom,prevProps,nextProps){// 移除旧的事件监听器Object.keys(prevProps).filter(keykey.startsWith(on)).forEach(name{consteventTypename.toLowerCase().substring(2);dom.removeEventListener(eventType,prevProps[name]);});// 移除旧的属性Object.keys(prevProps).filter(keykey!children!key.startsWith(on)).filter(key!(keyinnextProps)).forEach(name{dom[name];});// 设置新的属性和事件Object.keys(nextProps).filter(keykey!children).forEach(name{if(name.startsWith(on)){consteventTypename.toLowerCase().substring(2);dom.addEventListener(eventType,nextProps[name]);}else{dom[name]nextProps[name];}});}functionreconcile(parentDom,oldNode,newNode,index0){if(!oldNodenewNode){constdomcreateDom(newNode);parentDom.appendChild(dom);returndom;}if(oldNode!newNode){parentDom.removeChild(parentDom.childNodes[index]);returnnull;}if(oldNode.type!newNode.type){constdomcreateDom(newNode);parentDom.replaceChild(dom,parentDom.childNodes[index]);returndom;}constdomparentDom.childNodes[index];updateDom(dom,oldNode.props,newNode.props);constoldChildrenoldNode.props.children||[];constnewChildrennewNode.props.children||[];constmaxLengthMath.max(oldChildren.length,newChildren.length);for(leti0;imaxLength;i){reconcile(dom,oldChildren[i],newChildren[i],i);}returndom;}functionrender(element,container){currentContainercontainer;reconcile(container,null,element);}functionrerender(){hookIndex0;// 重置hook索引currentContainer.innerHTML;// 清空容器render(currentComponent(),currentContainer);// 重新渲染}functionuseState(initialValue){constindexhookIndex;if(hooks[index]undefined){hooks[index]initialValue;}conststatehooks[index];constsetState(newValue){hooks[index]typeofnewValuefunction?newValue(hooks[index]):newValue;rerender();};hookIndex;return[state,setState];}constMiniReact{createElement,render,useState};使用示例体验我们亲手打造的 React!DOCTYPEhtmlhtmlheadtitleMini React 体验/titlestylebody{font-family:Arial;padding:20px;}.counter{margin:20px0;padding:20px;background:#f5f5f5;}button{margin:5px;padding:8px 16px;}/style/headbodyh1亲手实现的React/h1div idroot/divscript srcmini-react.js/scriptscript// 告诉编译器使用我们的createElement处理JSX/** jsx MiniReact.createElement */functionCounter(){const[count,setCount]MiniReact.useState(0);const[name,setName]MiniReact.useState(React);return(div classNamecounterh2欢迎使用{name}/h2p当前计数:{count}/pdivbutton onClick{()setCount(count1)}增加/buttonbutton onClick{()setCount(count-1)}减少/buttonbutton onClick{()setName(nameReact?MiniReact:React)}切换名称/button/div/div);}// 保存当前组件和容器供重新渲染使用currentComponentCounter;// 首次渲染MiniReact.render(Counter/,document.getElementById(root));/script/body/htmlReact 原理的三层理解第一层概念理解虚拟 DOM 是 UI 的 JavaScript 描述协调算法是比较新旧虚拟 DOM 的差异组件是返回虚拟 DOM 的函数第二层实现理解我们今天达到的虚拟 DOM 如何创建和渲染协调算法的四种情况处理Hooks 基于调用顺序的状态管理第三层优化理解真实 React 做的​Fiber 架构​可中断的渲染过程支持时间切片​批量更新​合并多个 setState 调用​优先级调度​高优先级更新先执行​Key 优化​更智能的子节点复用从迷你 React 到真实 React 开发理解了这些原理你在实际开发中就能​写出高性能代码​知道什么会导致不必要的重新渲染​快速定位问题​当 UI 更新异常时知道从哪里排查​合理使用 Hooks​理解依赖数组、useMemo 等高级用法的本质​设计更好的组件​基于 React 的更新机制设计组件结构总结React 不是魔法只是聪明的设计通过 300 行代码我们揭开了 React 的神秘面纱。现在你知道了虚拟 DOM只是一个普通对象描述了 UI 结构协调算法通过比较决定最小更新而不是全部重绘Hooks通过调用顺序管理状态因此有那些使用限制理解原理不是为了炫技而是为了​写出更可靠的代码​知道 React 如何工作避免踩坑​高效调试问题​当 UI 异常时能快速定位原因​做出合理设计​基于 React 特性设计应用架构​最好的学习方式是实践​修改这个迷你 React添加新功能遇到问题并解决它。这会比阅读任何文章都让你更深入理解 React。