【一】实现createElement - 手写 mini react

86 阅读1分钟

前言

在前端的 React 面试中,基本都会涉及到 React 工作原理这一重要内容。快速且深入地掌握 React 工作原理,能够显著提高面试的通过率。正因如此,本系列将通过实现极为简单的 =mini react 来深入探究 React 的工作原理,期望能够持之以恒,与大家携手学习、共同进步。

JSX 语法与 React 元素

JSX 语法

其表现形式类似于<span>hello {name}</span>这样的语法糖。本质上,它是一种语法糖,在编译打包后会被 Babel 编译成 React.createElement,用于创建 React 元素。

React 元素

本质上是一个 JSON 对象,是由 React.createElement 函数所返回的对象。其结构大致如下,核心属性包括 type 和 props 等。

interface IReactElement {
  type: string;
  props?: {
    className?: string,
    style?: CSSProperties,
    children?: IReactElement | IReactElement[],
  }
}

开发阶段 - jsx

const Counter = () => {
  const [count, setCount] = useState(0);
  return (
    <div>
      <span>{count}</span>
      <button onClick={() => setCount(count + 1)}>+</button>
      <button onClick={() => setCount(count - 1)}>-</button>
    </div>
  );
};

编译阶段 - createElement

const Counter = (props) => {
  const [count, setCount] = useState(0);
  return createElement('div', {
    children: [
      createElement('span', { children: count }),
      createElement('button', { children: '+', onClick: () => setCount(count + 1)  }),
      createElement('button', { children: '-', onClick: () setCount(count - 1)  }),
    ]
  }, count, createElement('div', null, props.name));
}

jsx 语法本质是 createElement 语法糖

源码实现

function createElement(type, props,...children) {
  return {
    type,
    props: {
    ...props,
      children: children.map((child) => {
        return typeof child === 'object'? child : createTextElement(child)
      })
    }
  }
}

// 如果传入的是纯文字,不想转成 innerText 模式,因此需要 createTextElement
function createTextElement(text) {
  return {
    type: 'TEXT_ELEMENT',
    props: {
      nodeValue: text,
      children: []
    }
  }
}

export {
  createElement
};