当前位置: 首页 > news >正文

react 源码2

useCallback useMemo useContext createContext

新增了一些hook。

// 创建虚拟dom的函数 
// 函数组件会被babel最初解析成一个特殊的对象,因为还没有运行函数
// function createElement(type, props, ...children) {
//   // console.log(type)
//   return {
//     type,
//     props: {
//       ...props,
//       children: children.map((child) =>
//         typeof child === "object" ? child : createTextElement(child)
//       ),
//     },
//   };
// }function createElement(type, props, ...children) {// console.log("debug: ", children, children.flat()); return {type, props: {...(props || {}), children: children.flat().map(i => typeof i === 'object' && i !== null ? i : createTextElement(i))}}
}function createTextElement(text) {return {type: "TEXT_ELEMENT",props: {nodeValue: text,children: [],},};
}function createDom(fiber) {const dom =fiber.type == "TEXT_ELEMENT"? document.createTextNode(""): document.createElement(fiber.type);updateDom(dom, {}, fiber.props || {});return dom;
}const isEvent = (key) => key.startsWith("on");
const isProperty = (key) => key !== "children" && !isEvent(key);
const isNew = (prev, next) => (key) => prev[key] !== next[key];
const isGone = (prev, next) => (key) => !(key in next);
function updateDom(dom, prevProps, nextProps) {prevProps = prevProps || {}; nextProps = nextProps || {}; //Remove old or changed event listenersObject.keys(prevProps).filter(isEvent).filter((key) => !(key in nextProps) || isNew(prevProps, nextProps)(key)).forEach((name) => {const eventType = name.toLowerCase().substring(2);dom.removeEventListener(eventType, prevProps[name]);});// Remove old propertiesObject.keys(prevProps).filter(isProperty).filter(isGone(prevProps, nextProps)).forEach((name) => {dom[name] = "";});// Set new or changed propertiesObject.keys(nextProps).filter(isProperty).filter(isNew(prevProps, nextProps)).forEach((name) => {dom[name] = nextProps[name];});// Add event listenersObject.keys(nextProps).filter(isEvent).filter(isNew(prevProps, nextProps)).forEach((name) => {const eventType = name.toLowerCase().substring(2);dom.addEventListener(eventType, nextProps[name]);});
}function commitEffects() {const _ = (fiber) => {if(!fiber || fiber === null) return;if(fiber && fiber.hooks && fiber.type instanceof Function) {fiber.hooks.filter(hk => hk.isEffect === true).forEach(hk => {let nx = null; if(hk.cb) {nx = hk.cb();hk.cb = null;}if(nx) {if(hk.clean) hk.clean(); hk.clean = nx; }});}_(fiber.child);_(fiber.sibling);};_(wipRoot);
}function commitRoot() {deletions.forEach(commitWork);commitWork(wipRoot.child);commitEffects();currentRoot = wipRoot;wipRoot = null;
}function commitWork(fiber) {if (!fiber) {return;}let domParentFiber = fiber.parent;// console.log("si: ", fiber.parent)while (!domParentFiber.dom) {domParentFiber = domParentFiber.parent;}const domParent = domParentFiber.dom; // 找到第一个有真实dom的元素if (fiber.effectTag === "PLACEMENT" && fiber.dom != null) {domParent.appendChild(fiber.dom);} else if (fiber.effectTag === "UPDATE" && fiber.dom != null) {updateDom(fiber.dom, fiber.alternate.props, fiber.props);} else if (fiber.effectTag === "DELETION") {commitDeletion(fiber, domParent);}commitWork(fiber.child);commitWork(fiber.sibling);
}function commitDeletion(fiber, domParent) {if (fiber.dom) {domParent.removeChild(fiber.dom);} else {commitDeletion(fiber.child, domParent);}
}// 将element部署到container上,只会在加载页面的时候进行一次。
function render(element, container) {// console.log("debug: ", element, container);// console.log("debug: ", currentRoot);// 初始化工作区的fiber-treewipRoot = {dom: container, // rootprops: {children: [element],},alternate: currentRoot,};deletions = []; // 需要删除的元素nextUnitOfWork = wipRoot; // 下一个需要工作的fiber节点
}let nextUnitOfWork = null; // 下一次工作的目标fiber,初始化为null
let currentRoot = null; // 当前渲染的fiber-dom树
let wipRoot = null; // 正在工作的fiber-dom树
let deletions = null; // 需要删除的元素的数组// 工作片,最小工作单元
function workLoop(deadline) {// console.log(deadline);let shouldYield = false; // 初始化为false,当为ture的时候需要暂停// 当有下一个工作的单元并且不需要暂停时while (nextUnitOfWork && !shouldYield) {nextUnitOfWork = performUnitOfWork(nextUnitOfWork); // 执行nextUnitOfWorkshouldYield = deadline.timeRemaining() < 1;}if (!nextUnitOfWork && wipRoot) {commitRoot();}requestIdleCallback(workLoop);
}// 浏览器函数,每次自动运行回调
requestIdleCallback(workLoop);// 执行fiber任务的函数,返回下一个工作的单元
function performUnitOfWork(fiber) {const isFunctionComponent = fiber.type instanceof Function;if (isFunctionComponent) {// 函数组件:updateFunctionComponent(fiber);} else {// 原始标签updateHostComponent(fiber);}if (fiber.child) {return fiber.child;}let nextFiber = fiber;while (nextFiber) {if (nextFiber.sibling) {return nextFiber.sibling;}nextFiber = nextFiber.parent;}
}let wipFiber = null; // 当前工作的wib-fiber
let hookIndex = null;function updateFunctionComponent(fiber) {wipFiber = fiber;hookIndex = 0;wipFiber.hooks = [];const children = [fiber.type(fiber.props)]; // 函数组件返回的jsx元素reconcileChildren(fiber, children.flat()); 
}
/**useEffect(() => {console.log("执行");}, [])  
*/
function useEffect(f = () => {}, arr = []) {const oldHook = wipFiber.alternate && wipFiber.alternate.hooks&& wipFiber.alternate.hooks[hookIndex];  // 拿到旧的Effectlet flag = false;if(!oldHook || (oldHook.deps && (oldHook.deps.length !== arr.length|| oldHook.deps.some((i, idx) => (i !== arr[idx]))))) flag = true; console.log(flag)const hook = {deps: arr, cb: flag ? f : null, clean: oldHook ? oldHook.clean : null, isEffect: true};if(!wipFiber.hooks) wipFiber.hooks = []; wipFiber.hooks.push(hook); hookIndex ++; 
}function useMemo(calc, deps) {const oldHook =wipFiber.alternate &&wipFiber.alternate.hooks &&wipFiber.alternate.hooks[hookIndex];let flag = false; if(!oldHook || (Array.isArray(oldHook.deps) && (oldHook.deps.length !== deps.length || oldHook.deps.some((i, idx) => i !== deps[idx]))) ) flag = true;const hook = {deps, result: flag ? calc() : oldHook.result}if(!Array.isArray(wipFiber.hooks)) wipFiber.hooks = [];wipFiber.hooks.push(hook);hookIndex ++; return hook.result;
} function useCallback(fn, deps) {const oldHook =wipFiber.alternate &&wipFiber.alternate.hooks &&wipFiber.alternate.hooks[hookIndex];let flag = false; if(!oldHook || (Array.isArray(oldHook.deps) && (oldHook.deps.length !== deps.length || oldHook.deps.some((i, idx) => i !== deps[idx]))) ) flag = true;// console.log(oldHook?.deps, deps, oldHook?.deps?.length !== deps, //    oldHook?.deps?.some((i, idx) => i !== deps[idx])// )const hook = {deps, result: flag ? fn : oldHook.result};if(!Array.isArray(wipFiber.hooks)) wipFiber.hooks = [];wipFiber.hooks.push(hook);hookIndex ++; return hook.result;
}function useRef(initilal) {const oldHook =wipFiber.alternate &&wipFiber.alternate.hooks &&wipFiber.alternate.hooks[hookIndex];const hook = {current: oldHook ? oldHook.current : initilal, }; if(!Array.isArray(wipFiber.hooks)) wipFiber.hooks = []; wipFiber.hooks.push(hook);hookIndex ++;return hook;
} function useState(initial) {const oldHook =wipFiber.alternate &&wipFiber.alternate.hooks &&wipFiber.alternate.hooks[hookIndex];const hook = {state: oldHook ? oldHook.state : initial,queue: [],};const actions = oldHook ? oldHook.queue : [];actions.forEach((action) => {hook.state = action(hook.state);});const setState = (action) => {hook.queue.push(action);wipRoot = {dom: currentRoot.dom,props: currentRoot.props,alternate: currentRoot,};nextUnitOfWork = wipRoot;deletions = [];};wipFiber.hooks.push(hook);hookIndex++;return [hook.state, setState];
}// reducer
function useReducer(reducer, initialState, init) {const [state, setState] = useState(init ? init(initialState) : initialState);const dispatch = (action) => {setState(prev => reducer(prev, action));}; return [state, dispatch];
}// 创建一个上下文
function createContext(defaultValue) {function Provider(props) {return {type: Provider,props: props};}const context = {_defaultValue: defaultValue, Provider: Provider,_id: Symbol("context")}; return context;
}function useContext(context) {let fiber = wipFiber;while (fiber && fiber.parent) {fiber = fiber.parent;if(fiber.type === context.Provider) {const hook = {context, value: fiber.props.value };wipFiber.hooks = wipFiber.hooks || []; wipFiber.hooks.push(hook); hookIndex ++; return fiber.props.value;}}const hook = {context, value: context._defaultValue}; wipFiber.hooks = wipFiber.hooks || []; wipFiber.hooks.push(hook); hookIndex ++; return hook.value;
}function updateHostComponent(fiber) {if (!fiber.dom) {fiber.dom = createDom(fiber);}reconcileChildren(fiber, fiber.props.children);
}// 当前的fiber, 新节点的子元素 
function reconcileChildren(wipFiber, elements) {/*** diff 算法:* 给定两个列表,每个元素都有自己的key,要求尽可能复用原本的元素。* 对所有的key-type哈希成数值/带字母的,映射到它们对应的新的节点的索引上面,无key值的只能将其删除重新创建dom* map, 字典树*/let index = 0;// 通过alternate链接旧的fiberlet oldFiber = wipFiber.alternate && wipFiber.alternate.child;let prevSibling = null;// console.log("reconcileChildren: ", oldFiber, elements);// 遍历新的elements,并且去寻找新的while (index < elements.length || oldFiber != null) {const element = elements[index]; // 拿到新的节点,注意此时还没有更新let newFiber = null; // 新fiber的初始化// 判断两者是否相等const sameType = oldFiber && element && element.type == oldFiber.type;// 两者相等的时候,可以复用真实dom,改下props就好。if (sameType) {newFiber = {type: oldFiber.type, // 复用,因为相等props: element.props,dom: oldFiber.dom,parent: wipFiber,alternate: oldFiber, effectTag: "UPDATE", // 标记为UPDATE };}if (element && !sameType) {// console.log("替换 ", );newFiber = {type: element.type,props: element.props,dom: null,parent: wipFiber,alternate: null,effectTag: "PLACEMENT",    // 替还原来的点};}if (oldFiber && !sameType) {oldFiber.effectTag = "DELETION"; deletions.push(oldFiber);}if (oldFiber) {oldFiber = oldFiber.sibling;}if (index === 0) {wipFiber.child = newFiber;} else if (element) {prevSibling.sibling = newFiber;}prevSibling = newFiber;index++;}
}const Didact = {createElement,render,useState,useEffect, useRef, useMemo, useCallback
};/** @jsx Didact.createElement */
function Foo() {const [s1, setS1] = Didact.useState(2);return (<div><div onClick={() => setS1((c) => (c += "1"))}>code__ccc</div><h2> {s1} </h2></div>);
}let last = null; 
/** @jsx Didact.createElement */
function Counter() {const [state, setState] = Didact.useState(1);const [isShow, setShow] = Didact.useState(true);Didact.useEffect(() => {console.log("count发生了改变", state);}, [state]);const f1 = Didact.useCallback(() => {}, []); console.log("debug: ", last === f1);last = f1; const ref = Didact.useRef(2);return (<div><h1 onClick={() => setState((c) => c + 1)} style="user-select: none">Count: {state}{/* <Foo /> */}</h1>{[1, 2, 3, 4].map((i, idx) => <li key={idx}>{i}</li>)} {null}<div>{isShow ? <div>这个是一个div</div> : null}</div><button onClick={() => {setShow((isShow) => {console.log("执行了");return !isShow;});}}>按钮</button><h2>这是一个不会重新渲染的值: {ref.current}</h2><buttononClick={() => {ref.current = 3;}}>操控ref</button></div>);
}const element = <Counter x={1} />;
// const ele = <p>急啊纠结啊</p>; 
const container = document.getElementById("root");
Didact.render(element, container);
http://www.dtcms.com/a/552729.html

相关文章:

  • 淮南电商网站建设苏州网站优化
  • AI应用市场崛起:聊天机器人、教育学习、视频创作三驾马车驱动创新
  • SQL 学习笔记
  • 医药网站建设中图片app开发公司 弙东
  • ProfiNet转ModbusTCP实战:工业智能网关让S7-1516与上位机3ms握手
  • 巨 椰 云手机和云真机哪个个比较好用?
  • 云手机中的数据信息会被泄露吗
  • 百度快照举报网站威海企业网站建设
  • 16.React性能优化SCU
  • Linux系统C++开发环境搭建工具(三)—— brpc使用指南
  • 《静态库与动态库:从编译原理到实战调用,一篇文章讲透》
  • 标签绑定货物信息误删处理
  • 划时代的AI Agent qwen的回答和思考
  • Rust中泛型函数实现不同类型数据的比较
  • 19. React的高阶组件
  • 中小企业建站服务外贸建站模板免费
  • 网站域名多少钱一年wordpress 发布 工具
  • 个人备案网站可以做淘宝客吗codex.wordpress.org
  • 做网络推广自己建网站建设局局长权力大吗
  • 外贸网站建设需求无锡做网站设计
  • 泰安网站建设策划方案wordpress 评论模版
  • 论坛网站用的虚拟主机做网站需要先学什么
  • 佛山网站推广seo定制网站开发流程图
  • 慈溪市住房和城乡建设局网站营销型网站建设需要懂什么软件
  • 参考网是正规网站吗平面设计大师
  • 网站策划书wordpress群
  • 查看网站开发平台苏州最新情况最新消息今天
  • 攀枝花网站建设兼职wap网站乱码
  • 开封景区网站建设项目方案婚纱摄影网站建站
  • 购物网站 购物车界面如何做访问网站提示输入用户名密码