MiniReact系列之实现一个简易createElement(一)

299 阅读2分钟

前言

最近正在学习,学习,还是学习。。。。越学习越觉得自己啥都不会,有点焦虑了。。。决定开始尝试写写博客文章,记录下学习过程,废话不说了,开始吧!

地址:github.com/nocodig/min…

正文

React的jsx语法会通过babel编译成React.createElement(至于咋编译的我现在也不知道🐶)但是我们要实现一个这个方法需要让让jsx语法调用我们的createElement,需要对babel进行特殊配置,配置如下:

{
  "presets": [
    "@babel/preset-env",
    [
      "@babel/preset-react",
      {
        "pragma": "MiniReact.createElement" //重点在这
      }
    ]
  ]
}

官方文档createElement参数如下:

  • type:标签名称或者React组件类型
  • props:组件或者节点上的参数比如class等
  • children:子节点

一、乞丐版

那么我们基本参数就根据文档定义,同样接收三个参数,并且将他们直接返回出去,而且我们可以通过props访问到children,将children添加到props中去

function createElement(type, props, ...children) {
  return {
    type,
    props: { ...props, children}
    children
  }
}

返回是这样婶的(通过配置babel,调用我们自己的createElement)

呃。。。。。好像有点不太对(乞丐版就别纠结那么多了)。。。。虚拟DOM的本质上一个对象,但是上面也不是对象,而且对于布尔值不应该渲染在视图内,所以这个时候需要进行特殊处理下。有了下面的升级版

二、升级版

需要考虑下面场景

  • 直接是一个文本节点,那么此时需要将文本转化成一个对象
  • 在编写过程中,一些节点是bool值或者是null,需要将这部分值去除

先考虑第一种情况,这个时候我们需要对children参数进行遍历,判断是不是对象即可!(好像解决了第一种情况)

function createElement(type, props, ...children) {
  const childrenItems = [].concat(children).reduce((result, item) => {
    if (item instanceof Object) {
      result.push(item)
    } else {
      result.push(createElement('text', { textContent: item }))
    }

    return result
   
  },[])

  return {
    type,
    props: { ...props, children: childrenItems},
    children: childrenItems
  }

至于第二种情况,我们需要过滤将children中的bool类型值过滤出去就好,那么如果item值 不是布尔类型或者null的时候,不去执行上面代码中的对result添加值即可

function createElement(type, props, ...children) {
  const childrenItems = [].concat(children).reduce((result, item) => {
    if (item !== false && item!==null && item!==true) {
      if (item instanceof Object) {
        result.push(item)
      } else {
        result.push(createElement('text', { textContent: item }))
      }
    }

    return result
   
  },[])

  return {
    type,
    props: { ...props, children: childrenItems},
    children: childrenItems
  }
}

先暂时进行到这,未完继续(困了,该睡觉了,虽然有点焦虑,身体重要,拒绝内卷)