Skip to content

实现函数组件 ​

本节目标:理解“实现函数组件”的核心思路,并能把它用于实际开发或面试表达。

src\index.js
import React from "./react";
import ReactDOM from "./react-dom";
function FunctionComponent(props) {
  return (
    <div
      className="title"
      style={{ color: 'red' }}
    >
      <span>{props.name}</span>
      {props.children}
    </div>
  );
}
let element = <FunctionComponent name="hello">world</FunctionComponent>;
ReactDOM.render(element, document.getElementById("root"));

由于函数组件是通过函数声明或表达式声明的,又加上名字为大写的约定,所以babel在分析jsx时,就会将type值设置为这个变量所代表函数,这时typeof这个变量肯定是函数; 修改

src\react-dom.js
import { REACT_TEXT } from "./constants";
function render(vdom, container) {
  mount(vdom, container);
}
export function mount(vdom, container) {
  let newDOM = createDOM(vdom);
  container.appendChild(newDOM);
}

在createDOM的时候多加一个判断,即type为function时,进行特殊处理 /**

  • 把虚拟DOM转成真实DOM */ export function createDOM(vdom) { if (!vdom) return null; let { type, props } = vdom; let dom;//真实DOM if (type === REACT_TEXT) {//如果这个元素是一个文本的话 dom = document.createTextNode(props.content); } ==else== ==if== ==(====typeof== ==type== ======= =='function'====) {====//====如果类型是一个函数的话== ==if== ==(====type====.====isReactComponent====) {====//====说明它是一个类组件== ==return== ==mountClassComponent====(====vdom====);== ==}== ==else== =={== ==return== ==mountFunctionComponent====(====vdom====);== ==}== ==}== else { dom = document.createElement(type);// div span p } //处理属性 if (props) { updateProps(dom, {}, props); if (props.children) { let children = props.children; if (typeof children === 'object' && children.type) {//说明这是一个React元素 mount(children, dom); } else if (Array.isArray(children)) { reconcileChildren(props.children, dom); } } } vdom.dom = dom;//让虚拟DOM的dom属性指向这个虚拟DOM对应的真实DOM return dom; }

主要是做以下事件:

  • 调用函数,并传入props值,这样取得函数的返回值;
  • 这个函数的返回值就是函数组件的vdom;
  • 将vdom以属性名oldRenderVdom挂靠到函数组件自身的vdom上;
  • 使用函数组件返回的renderVdom创建真实dom,并将其返回;
  • 这个返回的dom会被挂载到父dom下;
function mountFunctionComponent(vdom) {
  let { type, props } = vdom;
  let renderVdom = type(props);
  vdom.oldRenderVdom = renderVdom;
  return createDOM(renderVdom);
}
function updateProps(dom, oldProps, newProps) {
  for (let key in newProps) {
    if (key === "children") {
      continue;
    }
    if (key === "style") {
      let style = newProps[key];
      for (let attr in style) {
        dom.style[attr] = style[attr];
      }
    } else {
      dom[key] = newProps[key];
    }
  }
}
function reconcileChildren(childrenVdom, parentDOM) {
  for (let i = 0; i < childrenVdom.length; i) {
    let childVdom = childrenVdom[i];
    mount(childVdom, parentDOM);
  }
}
const ReactDOM = {
  render,
};
export default ReactDOM;

本站总访问 — 次