Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Buzz-React

徒手写一个基于 Fiber 和 Hooks 的 React Likely Framework

简介

完成了基础 Fiber、Hooks 的功能,目的只是为了学习 React 相关知识,从底层开始了解 React 的运行机制

主流程

渲染主流程

fiber 架构就分为了 schdule、reconcile(vdom 转 fiber)、commit(更新到 dom)三个阶段,vdom 转 fiber 的过程叫做 reconcile,最后增删改真实 dom 的过程叫做 commit。

Hooks 实现

VDOM 到 Fiber 的过程,Hooks 状态保存到 FC Fiber 节点,hooks 状态存放在 FC 的 FiberRoot 节点上。

useState

/**
 * 1. 为当前 hook 设置索引位置,新增or使用上一次 hook state
 * 2. 回调执行后更新 fiber 数,让 schdule 更新数
 * @param {any} initialState 
 * @returns 
 */
const useState = (initialState) => {
  const oldHook =
    wipFiber.alternate &&
    wipFiber.alternate.hooks &&
    wipFiber.alternate.hooks[hookIndex];
  const hook = {
    state: oldHook ? oldHook.state : initialState,
    queue: []
  };

  const actions = oldHook ? oldHook.queue : [];
  actions.forEach((action) => {
    hook.state = action(hook.state);
  });

  const setState = (actionCallback) => {
    const action = typeof actionCallback !== 'function' ? () => actionCallback : actionCallback;

    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];
};

useRef

把数据保存在 hook 上,上屏操作时把 DOM 指向 fiber.props.ref.current 上

const useRef = (initialValue) => {
  const oldHook = wipFiber?.alternate?.hooks?.[hookIndex];
  const ref = { current: initialValue };
  const hook = {
    state: oldHook?.state || ref
  };

  wipFiber.hooks.push(hook);
  hookIndex ++;
  return ref;
};

const updateHostComponent = (fiber) => {
  if (!fiber.dom) {
    fiber.dom = createDOM(fiber);
    
    if (fiber?.props?.ref) {
      fiber.props.ref.current = fiber.dom;
    }
  }

  reconcileChildren(fiber, fiber.props.children);
};

useEffect

两个参数,第一个是回调,第二是监听的数据,关键点:

function useEffect(effect, deps) {
  const oldHook = wipFiber?.alternate?.hooks?.[hookIndex];
  const hasChanged = hasDepsChanged(oldHook?.deps ?? undefined, deps);
  const hook = {
    tag: "effect",
    effect: hasChanged ? effect : null,
    cancel: hasChanged && oldHook?.cancel,
    deps,
  };

  wipFiber.hooks.push(hook);
  hookIndex++;
}

// commitWork 阶段需要做DOM的回调
......
if (fiber.effectTag === "PLACEMENT") {
  if (dom != null) {
    domParent.appendChild(dom);
  }
  runEffects(fiber);
} else if (fiber.effectTag === "UPDATE") {
  cancelEffects(fiber);
  if (fiber.dom !== null) {
    updateDom(dom, fiber.alternate.props, fiber.props);
  }
  runEffects(fiber);
} else if (fiber.effectTag === "DELETION") {
  cancelEffects(fiber);
  commitDeletion(fiber, domParent);
  return;
}
......

About

Use pure JavaScript implement simple React Framework.

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages