由下面的例子可以看出,函数式组件实际上是一个函数,执行此函数可以获得一个dom

const Counter = ({num}) => {
    return (
        <div>Counter: {num}</div>
    )
}

因此,在生成dom的相关逻辑中,可以针对此特性进行判断。

要考虑到函数组件的传参,所以在执行函数组件的时候要降props传进去。在创建dom的地方做一下兼容

const createElement = (type, props, ...children) => {
    return {
        type,
        props: {
            ...props,
            children: children.map(child => {
								// 针对传参进行兼容
                const isTextNode = typeof child === 'string' || typeof child === 'number'
                return isTextNode ? createTextEl(child) : child
            })
        }
    }
}

函数组件生成dom

function perfromFiberOfUnit(fiber){
		// 判断当前dom是不是函数组件,不是才执行创建dom方法
    const isFunctionComponrnt = typeof fiber.type === 'function'
    if(!isFunctionComponrnt){
        if(!fiber.dom){
            // 1.创建dom节点
						// ...
            // 2.设置props
            // ...
        }
    }
		// 因为执行函数组件将直接得到dom,所以需要手动包裹成数组,并将对应的props传进去
		const children = isFunctionComponrnt ? [fiber.type(fiber.props)] : fiber.props.children

		// 转化成链表,做好指针关系
		// ...
}

这样就基本上完成了对function component的实现。

相关理解:

函数组件相当于是一个盒子,执行函数组件就是开盒的过程,开盒完成后就可以获取到对应的dom,但是函数组件会留在dom树中,所以要考虑到函数组件没有真实dom,并不能挂载的情况。

Untitled

因此有一些前置优化的地方来做个提醒:

function commitWork(work){
    // ...

		// 兼容function component的情况。
		// 因为在function component的dom节点是null,所以要循环往上查找真实的dom并挂载
    while(!parentWork.dom){
        parentWork = parentWork.parent
    }

    // ...
}