1、前言

我们先来编写一个函数组件:

  1. // src/index
  2. import React from '../react'
  3. function App(props){
  4. return <h1>H1,{props.name}!</h1>
  5. }
  6. const element = (<App name='foo'></App>)
  7. React.render(element, document.getElementById("root"))

函数组件的和标签组件有乱两个不同点:

  • 函数组件中的fiber没有DOM节点
  • children是通过运行函数得到的而不是props

2、功能实现

2.1 performUnitOfWork添加判断函数组件;

  1. function performUnitOfWork(fiber) {
  2. // 判断是否为函数
  3. const isFunctionComponent =
  4. fiber.type instanceof Function
  5. if (isFunctionComponent) {
  6. updateFunctionComponent(fiber)
  7. } else {
  8. // 更新普通节点
  9. updateHostComponent(fiber)
  10. }
  11. // 省略
  12. }
  13. function updateFunctionComponent(fiber) {
  14. // TODO
  15. }
  16. function updateHostComponent(fiber) {
  17. // TODO
  18. }

2.2 抽离performUnitOfWork中的reconcileChildren方法到updateHostComponent函数;

  1. function updateHostComponent(fiber) {
  2. if (!fiber.dom) {
  3. fiber.dom = createDom(fiber)
  4. }
  5. reconcileChildren(fiber, fiber.props.children)
  6. }

2.3 处理函数组件,执行函数组件来获取children;

  1. /**
  2. * 函数组件处理
  3. * @param {*} fiber
  4. */
  5. function updateFunctionComponent(fiber) {
  6. const children = [fiber.type(fiber.props)]
  7. reconcileChildren(fiber, children)
  8. }


2.4 接下来我们处理一下没有DOM的fiber;

  1. function commitWork (fiber) {
  2. // 省略
  3. let domParentFiber = fiber.parent
  4. // 一直向上找直到找到有dom的节点
  5. while (!domParentFiber.dom) {
  6. domParentFiber = domParentFiber.parent
  7. }
  8. const domParent = domParentFiber.dom
  9. // 省略
  10. }

2.5 当移除一个节点时,需要不断的向下找,直到找到一个具有 DOM 节点的子节点。

  1. /**
  2. * 处理提交的fiber树
  3. * @param {*} fiber
  4. * @returns
  5. */
  6. function commitWork(fiber) {
  7. // 省略
  8. // 处理删除节点标记
  9. } else if (fiber.effectTag === "DELETION") {
  10. commitDeletion(fiber, domParent)
  11. }
  12. // 省略
  13. }
  14. /**
  15. * 删除情况下,不断的向下找,直到找到有dom的子节点
  16. * @param {*} fiber
  17. * @param {*} domParent
  18. */
  19. function commitDeletion(fiber, domParent) {
  20. if (fiber.dom) {
  21. domParent.removeChild(fiber.dom)
  22. } else {
  23. commitDeletion(fiber.child, domParent)
  24. }
  25. }

3、实现效果

image.png

4、本节代码

代码地址:https://github.com/linhexs/mini-react/tree/7.function