react 学习(二) 实现类和函数式组件

2022-04-06 21:52:57 浏览数 (1)

我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调用函数返回虚拟 dom,一个是调用实例的 render 方法,返回虚拟 dom,进而转换为真实 dom,本小节我们了解一下具体的实现原理。

函数式组件

特点

  1. 函数组件接受一个单一的 props 对象并返回一个 react 元素
  2. 组件以大写字母开头(内部判断是原生还是自定义)
  3. 组件必须在使用时定义或引用
  4. 组件返回值只能有一个根元素(便于树遍历)
  5. React 元素不但可以使dom标签,也可以是用户自定义的组件
  6. react 元素为用户自定义组件时,他会将 jsx 接收的属性转换为单个对象换递给组件,即 props(babel 处理的)

使用

代码语言:txt复制
// index.js
function FunctionComponent(props) {
  let jsx = (
    <h1 className="title" style={{ color: "red", backgroundColor: "pink" }}>
      hello
      <span>111</span>
    </h1>
  );
  return jsx;
}
const el = <FunctionComponent msg='world' />;
console.log(el);
ReactDOM.render(el, document.getElementById("root"));

我们可以看到,函数组件返回的虚拟 dom 类型是函数类型,我们要修改我们的 createDOM 方法,实现函数式

实现

修改 createDOM 方法

代码语言:txt复制
// react-dom.js
...
if (typeof type === 'function') { // 上面截图我们看到函数组件的类型是个函数
  return mountFunctionComponent(vdom)
}
...


function mountFunctionComponent(vdom) {
  // 这里是 babel 编译时把我们写的属性转为了 props 对象形式
  const {type, props} = vdom
  const renderVdom = type(props)
  return createDOM(renderVdom)
}

入口文件改为自己的文件,打印如下:

类组件

react hooks 出现之前,想实现组件内容变化做不到,定义状态并改变状态只能使用类组件的方式。

使用

代码语言:txt复制
// index.js
class ClassComponent extends React.Component {
  render() {
    // 返回react 元素
    let jsx = (
      <h1 className="title" style={{ color: "red", backgroundColor: "pink" }}>
        hello
        <span>{this.props.msg}</span>
      </h1>
    );
    return jsx;
  }
}
const el = <ClassComponent msg="world" />;
console.log(el);
ReactDOM.render(el, document.getElementById("root"));

通过打印我们可以看到,类组件的类型是一个类。而且需要继承 React 对象的 Component 属性

实现

我们知道 javascript 本身是没有类的,es6 的类转化之后也会变成函数,这就会跟函数式组件的类型判断冲突,所以我们需要给类加上标识符

代码语言:txt复制
// react.js
// 我们逆推
const React = {
  createElement,
  Component
}

因为可以被继承,所以 Component 也是一个类

代码语言:txt复制
// src/Component.js
export class Component {
  static isReactComponent = REACT_COMPONENT; // 区分标识
  constructor(props) {
    this.props = props;
  }
}


// constants.js
export const REACT_COMPONENT = Symbol("react.component"); // Symbol 独一无二的  无法覆盖 无法伪造

我们改造一下 createDOM 方法

代码语言:txt复制
if (typeof type === "function") {
  // 类也是个函数
  if (type.isReactComponent === REACT_COMPONENT) {
    return mountClassComponent(vdom);
  }
  // 函数组件
  return mountFunctionComponent(vdom);
}


// 实现  mountClassComponent
function mountClassComponent(vdom) {
  const {type, props} = vdom
  const classInstance = new type(props) // 从打印中我们知道 type 是个类,可以被实例化
  const renderVdom = classInstance.render()
  return createDOM(renderVdom) // 虚拟dom转为真实dom
}

我们可以看到,无论是函数式组件还是类组件,本质都是返回处理的虚拟 dom,也就是基于上一小节的知识。这两个实现还不算复杂,跟着小编简单写写就可以掌握。下一小节我们学习下组件的更新机制,如果有不对,欢迎指正!

0 人点赞