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

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

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

在上一节 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系列二:渲染组件

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

查看所有标签

猜你喜欢:

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

Think Python

Think Python

Allen B. Downey / O'Reilly Media / 2012-8-23 / GBP 29.99

Think Python is an introduction to Python programming for students with no programming experience. It starts with the most basic concepts of programming, and is carefully designed to define all terms ......一起来看看 《Think Python》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

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

UNIX 时间戳转换

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具