实现一个react系列二:渲染组件

栏目: IOS · Android · 发布时间: 5年前

内容简介:在上一节在通过类定义组件时,是需要继承

在上一节 JSX和虚拟DOM 中,我们了解了 react 中的 JSX 到虚拟 dom ,以及如何将虚拟 dom 渲染成真实的 dom 。在这一节中,我们将会了解 react 中组件是如何渲染的。

组件

react 中,组件有两种使用方法:

import React from 'react'
// 类定义的组件
class Hello extends React.Component {
  render() {
    return <div>hello</div>
  }
}
// 无状态组件,通过函数来定义
const World = () => {
  return <h1>world!</h1>
}
ReactDom.render(<Hello />, document.getElementById('#root'))
复制代码

通过类定义组件时,是需要继承 React.component 的,我们第一步就从 React.Component 的实现开始。

类实现的组件有自己私有的 state ,同时可以通过 this.props 来获取传进来的参数。

function Component(props) {
  this.props = props
  this.state = {}
}
复制代码
  • setState

我们知道在 react 中,我们可以通过 setState 来改变组件 state 的值,而且当 state 改变后,组件对应的也会重新渲染。

  • 改变 state 的值:我们可以使用 Object.assign 来实现。
  • 重新渲染组件:我们可以在改变 state 值后,调用 render 函数,重新渲染。异步的 setState 在后面的章节会实现。
Component.prototype.setState = function (updateState) {
  // 更新 state
  this.state = Object.assign({}, this.state, updateState)
  // 重新渲染组件
  render(this)
}
复制代码

渲染

在上一节中,我们知道 ReactDom.render() ,会将其第一个参数转成 React.createElement() 形式,而组件也会被转为 React.createElement(Hello, null) 这种形式。

实现一个react系列二:渲染组件
所以 react 中组件在渲染时会被当成函数渲染的。所以我们在 render 函数中需要判断虚拟 dom 的标签属性(此处用 tag 表示的)是函数还是原生 dom 。如果是函数的话,我们只需要拿到组件的 jsx 转换后对应的虚拟 dom

, 然后在进行渲染。

const render = (vdom, root) => {
  if (typeof vdom.tag === 'function') {
    let component
    if (vdom.tag.prototype.render) {
      // 类定义的组件, vdom.attrs 是传入的 props
      component = new vdom.tag(vdom.attrs)
    } else {
      // 函数定义组件
      component = vdom.tag(vdom.attrs)
    }
    return _render(component, root)
  }
  _render(vdom, root)
}
复制代码

对应的_render():

const _render = (vdom, root) => {
  // 类组件的话,需要从 render 函数中拿到 jsx 转换后的虚拟 dom
  const vdomNode = vdom.render ? vdom.render() : vdom
  if (typeof vdomNode === "string" || typeof vdomNode === "number") {
    root.innerText += vdomNode
    return
  }
  const dom = document.createElement(vdomNode.tag)
  if (vdomNode.attrs) {
    for (let attr in vdomNode.attrs) {
      const value = vdomNode.attrs[attr]
      setAttribute(dom, attr, value)
    }
  }
  // 遍历子节点, 渲染子节点
  vdomNode.childs && vdomNode.childs.forEach(child => render(child, dom))
  // 将父节点 root 挂到 vdom 上,当再次渲染组件时,跟据 vdom.root 直接渲染 dom
  if (vdom.root) {
    vdom.root.innerText = ''
    vdom.root.appendChild(dom)
    return
  }
  vdom.root = root
  // 将子元素挂载到其真实 DOM 的父元素上
  root.appendChild(dom)
}
复制代码

试一试,刚出锅的代码效果如何。

import React from "./react"
import ReactDom from "./reactDom"

const World = props => {
  return (
    <h1>
      world!<p>{props.world}</p>
    </h1>
  )
}

class Hello extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      count: 0
    }
  }
  addCount() {
    const { count } = this.state
    this.setState({
      count: count + 1
    })
  }
  render() {
    return (
      <div ha="lou">
        hello
        <World world="function props" />
        <span>{this.props.initProps}</span>
        <div>{this.state.count}</div>
        <button onClick={this.addCount.bind(this)}> + </button>
      </div>
    )
  }
}

ReactDom.render(
  <Hello initProps="this is props" />,
  document.getElementById("root")
)

复制代码
实现一个react系列二:渲染组件

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

CSS揭秘

CSS揭秘

[希] Lea Verou / CSS魔法 / 人民邮电出版社 / 2016-4 / 99.00元

本书是一本注重实践的教程,作者为我们揭示了 47 个鲜为人知的 CSS 技巧,主要内容包括背景与边框、形状、 视觉效果、字体排印、用户体验、结构与布局、过渡与动画等。本书将带领读者循序渐进地探寻更优雅的解决方案,攻克每天都会遇到的各种网页样式难题。 本书的读者对象为前端工程师、网页开发人员。一起来看看 《CSS揭秘》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

SHA 加密
SHA 加密

SHA 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换