React 源码——day01

首先实现一个简单的 React 程序,打印一些元素

import React from "react";
import ReactDOM from "react-dom";
// let helloComponent = (
//   <div className="title" style={{ color: "red" }}>
//     <h1>hello</h1>world
//   </div>
// );
let helloComponent = React.createElement(
  "div",
  { className: "title", style: { color: "red" } },
  React.createElement("h1", {}, "hello"),
  "world"
);
console.log(JSON.stringify(helloComponent, null, 2));
ReactDOM.render(helloComponent, document.getElementById("root"));
{
  "type": "div",
  "key": null,
  "ref": null,
  "props": {
    "className": "title",
    "style": {
      "color": "red"
    },
    "children": [
      {
        "type": "h1",
        "key": null,
        "ref": null,
        "props": {
          "children": "hello"
        },
        "_owner": null,
        "_store": {}
      },
      "world"
    ]
  },
  "_owner": null,
  "_store": {}
}

实现 createElement()

  • 返回 virtualDOM 描述真实 DOM
function createElement(type, config, children) {
  if (config) {
    delete config.__source;
    delete config.__self;
  }
  let props = { ...config };
  if (arguments.length > 3) {
    children = Array.from(arguments).slice(2);
  }
  props.children = children;
  return {
    type,
    props,
  };
}
export default { createElement };

实现 createDOM()、render()

前置知识

类组件

  • 首字母要大写。小写的是原生组件,首字母大写的为自定义组件
  • 返回只有一个根元素的组件
  • 先定义,再使用

类组件如何渲染?

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { number: 0 };
  }
  handleClick = () => {
    this.setState({ number: this.state.number + 1 });
    console.log(this.state);
  };
  render() {
    return (
      <div>
        <p>number:{this.state.number}</p>
        <button onClick={this.handleClick}>点击</button>
      </div>
    );
  }
}
const counter = <Counter title="计数器" />
ReactDOM.render(counter, document.getElementById("root"));

1、const counter 定义类组件的元素

2、render() 创建类组件的实例, new Counter(props)

3、调用 render() ,得到一个 react 元素

4、转化成真实 DOM,插入到页面中


createDOM()、render() 源码实现
  • 考虑 virtualDOM 类型、stringnumberobjectarray
  • virtualDOM 节点上的属性、样式挂载到真实 DOM
function render(vdom, container) {
  const dom = createDOM(vdom);
  container.appendChild(dom);
}
function createDOM(vdom) {
  // 如果 vdom 是基本类型,说明是文本类型
  if (typeof vdom === "string" || typeof vdom === "number") {
    return document.createTextNode(vdom);
  }
  let { type, props } = vdom;
  let dom;
  // 类组件 Count解析的 type 为函数
  if (typeof type === "function") {
    if (type.isReactComponent) {
      // 区分该组件是 类组件
      return mountClassComponent(vdom);
    } else {
      // 函数式组件
      return mountFunctionComponent(vdom);
    }
  } else {
    dom = document.createElement(type);
  }
  updateDOMAttr(dom, props);
  if (
    typeof props.children === "string" ||
    typeof props.children === "number"
  ) {
    dom.textContent = props.children;
  } else if (typeof props.children == "object" && props.children.type) {
    // 如果单元素节点
    // 假如是这样的 children: { type: "div", props: {children: "hello"} }
    render(props.children, dom);
  } else if (Array.isArray(props.children)) {
    //是数组的话
    reconcileChildren(props.children, dom);
  } else {
    dom.textContent = props.children ? props.children.toString() : "";
  }
  vdom.dom = dom;
  return dom;
}
// 用于更新 DOM 节点的属性
function updateDOMAttr(dom, props) {
  for (let key in props) {
    if (key === "children") {
      continue;
    }
    if (key === "style") {
      for (let attr in props[key]) {
        dom.style[attr] = props[key][attr];
      }
    } else {
      dom[key] = props[key];
    }
  }
}
// 渲染 children 有多个元素的节点
function reconcileChildren(childrenVdom, parentDOM) {
  for (let i = 0; i < childrenVdom.length; i++) {
    let childVdom = childrenVdom[i];
    render(childVdom, parentDOM);
  }
}
function mountFunctionComponent(vdom) {
  const { type, props } = vdom;
  const renderVdom = type(props);
  return createDOM(renderVdom);
}
function mountClassComponent(vdom) {
  const { type, props } = vdom;
  const classInstance = new type(props);
  const renderVdom = classInstance.render(); // 虚拟 dom
  const dom = createDOM(renderVdom);
  classInstance.dom = dom;
  return dom;
}
export default {
  render,
};
  • 类组件在经过 babel转译之后,会将类转化成函数
  • 类组件会在 create-react-app 中将真实 DOM 解析为 vdom 结构
  • 在定义类组件时,会把 JSX 所有的属性封装成一个 props 对象传递给组件
  • 不管是类组件还是函数式组件 typeof type 都是一个 "function"。函数式组件不用说,类组件 class声明的类就是一个 function
  • jsx ? 是一种语法,打包的时候会进行编译,编译成 React.createElement() 的结果
  • React 元素指的就是虚拟 DOM,即普通的 JSX 对象,它描述了真实DOM
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值