内容简介:在上一节在通过类定义组件时,是需要继承
在上一节 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
中组件在渲染时会被当成函数渲染的。所以我们在
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") ) 复制代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 细说 Vue 组件的服务器端渲染
- (译)Vue.js 构建一个"无渲染"组件
- React 组件模式-有状态组件 x 无状态组件、容器组件 x 展示组件、高阶组件 x 渲染回调(函数作为子组件)
- React源码分析与实现(一):组件的初始化与渲染
- 支持大数据渲染下拉列表组件开发 SuperSelect(基于antd Select)
- reactjs – 使用react-router-dom进行组件渲染时更改Url?
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。