资讯专栏INFORMATION COLUMN

ReactDOM You Should

mo0n1andin / 745人阅读

摘要:并不是组件中的任何地方都能够使用获取结构,只对挂载后的组件生效。组件的一个特殊属性,接受一个回调函数作为参数。反之,则表示卸载失败。再看一下这段代码这个回调函数其实是没有参数的,但是,当方法变成异步方法之后,说不定就会向其注入一些参数了。

react的组件的开发过程中,一般来说,我们并不会真正的去操作dom。只有在顶层组件的渲染的过程中,我们借助ReactDOM.render()方法,将我们的应用渲染到html结构中。然而,由于react框架自身的限制,在某些特定的情况下,我们必须要手动的操作dom。这时,我们就需要使用ReactDOM了。

先说一个小事,在react 0.14版本的时候,ReactDOM就从react的核心库中分离出来了。所以,根据你使用的react版本的不同,我们引入ReactDOM的方式也就不一样。总而言之,也就下面两种基本的方法。

以下所有的代码,都会通过EcmaScript6进行编写

React < 0.14之前的版本

import React, { ReactDOM } from "react"

React >= 0.14之后的版本

yarn add react-dom
import ReactDOM from "react-dom"
ReactDOM的API

ReactDOM给我们提供了仅仅三个api。所以相对来说学习起来还是比较简单的。

这三个api 如下:

ReactDOM.findDOMNode

ReactDOM.unmountComponentAtNode

ReactDOM.render

下面,我们就简单的扯扯,这三个api我们应该怎么使用。

ReactDOM.findDOMNode

在絮叨这个api之前啊,先扯两个你应该知道的东西。

Q:DOM被真正添加到HTML中是什么时候?

A:生命周期方法componentDidMountcomponentDidUpdate

Q:还有没有其他获取DOM的方法

A:有,比如this.refs

说这干啥,就是为了告诉你应该什么时候去获取DOM。不要以为在任何地方都能获取,否则更多等待你的就是error * 3

好了,下面我们就好好扯扯findDOMNode该怎么用。

先看一下接口定义:

DOMElement findDOMNode(ReactComponent)

简单的说就是:给它一点绿荫(ReactComponent),还你一片森林(DOM Tree)。

比如,下面这个小demo,在组件加载完成的时候,获取真正的dom结构。

import React from "react";
import {findDOMNode, render} from "react-dom";

class App extends React.Component {
    constructor(props) {
        super(props)
        console.info("GET DOM IN %c constructor", "color:red")
        console.log(findDOMNode(this))
    }

    componentWillMount() {
        console.info("GET DOM IN %c componentWillMount", "color:red")
        console.log(findDOMNode(this))
    }

    componentDidMount() {
        console.info("GET DOM IN %c componentDidMount", "color:red")
        console.log(findDOMNode(this))
    }

    render() {
        return (
            
The menu
The person information
The content wrapper
The footer
) } } render(, document.getElementById("root"));

哎呀,惨不忍睹。

所以,把constructorfindDOMNode操作去掉,你会看到:

可以看出,在componentWillMountfindDOMNode的操作结果是null

但是,你会不会想,不是吧,返回null不能完全说明我没获取到元素啊。的确,比如:

import React from "react";
import {findDOMNode, render} from "react-dom";

class App extends React.Component {
    constructor(props) {
        super(props)
        // console.info("GET DOM IN %c constructor", "color:red")
        // console.log(findDOMNode(this))
    }

    componentWillMount() {
        console.info("GET DOM IN %c componentWillMount", "color:red")
        console.log(findDOMNode(this))
    }

    componentDidMount() {
        console.info("GET DOM IN %c componentDidMount", "color:red")
        console.log(findDOMNode(this))
    }

    render() {
        return null
    }
}

render(, document.getElementById("root"));

如你所愿,findDOMNode的操作结果都是null。但是,对比之中你应该清楚两件事。

并不是组件中的任何地方都能够使用findDOMNode获取DOM结构,findDOMNode只对挂载后的组件生效。

如果组件的render函数返回null,则在任何地方使用findDOMNode的结果都是null。

ReactDOM.findDOMNode with ref

先扯两句refref--组件的一个特殊属性,接受一个回调函数作为参数。两种情况:

给原生的html结构添加ref属性,其参数就是其对应的DOM元素。这时候,直接使用即可。

class声明的组件添加ref属性的时候,参数则是这个已经加载完成的react组件。这时候,就可以和findDOMNode来个亲密碰撞了。

如下面的操作:

import React from "react";
import {findDOMNode, render} from "react-dom";

class FieldInput extends React.Component {
    render() {
        return 
    }
}

class App extends React.Component {
    constructor(props) {
        super(props)
    }

    componentDidMount() {
        console.info("The value of %c this.input", "color:red")
        console.log(this.input)
        console.info("The value of %c findDOMNode(this.input)", "color:red")
        console.log(findDOMNode(this.input))
    }

    render() {
        return  { this.input = input }}
        />
    }
}

render(, document.getElementById("root"));

结果,就是你想的那样美好。

最后呢,记住一句话,findDOMNode不能用在函数式组件中哦

ReactDOM.unmountComponentAtNode

来先把接口的名称拆分一下:

unmount: 卸载

component: 组件

at: 在

node: 节点(DOM元素)

意思就是,从DOM元素中卸载已经挂载的组件,除此呢,还会清除它的事件处理器和state。来,看下面的代码:

import React, { Component } from "react";
import {findDOMNode, render, unmountComponentAtNode} from "react-dom";

class FieldOne extends Component {
    componentWillUnmount() {
        console.log("%c FieldOne will unmount")
    }
    render() {
        return 
The One
} } class FieldTwo extends Component { componentWillUnmount() { console.log("%c FieldTwo will unmount") } render() { return
The Two
} } class App extends Component { constructor(props) { super(props) } componentDidMount() { render(, this.fieldOne) } handleClick() { console.log(unmountComponentAtNode(this.fieldOne)) console.log(unmountComponentAtNode(this.fieldTwo)) } render() { return (
this.fieldOne = fieldOne}>
this.fieldTwo = fieldTwo}>
) } } render(, document.getElementById("root"))

简单的分析这段代码之前,先扯一个小的问题。react中的组件渲染有几种方式?一般来说,两种:

通过下面render函数,将组件渲染到DOM结构中。

React自身渲染

这两种渲染方式,分别对应于上述代码中的FieldOneFieldTwo组件的渲染方式。所以,你必须先搞明白一件事情,unmountComponentAtNode并不能卸载所有已经挂载到DOM中的组件,它只能卸载通过render函数渲染的组件。

所以,当我们点击button按钮的时候,会在控制台中看到,下面这些东西。

其中,当unmountComponentAtNode的返回值为true的时候,表示卸载成功。反之,则表示卸载失败。
下面是点击按钮之前的DOM结构的对比情况。
点击前

点击后

ReactDOM.render

react最让人爽的地方就是,接口名称的语意化很明显。所以,从字面意义上我们就能知道render是干啥的。干啥?用于渲染。

先简单的了解下接口定义。

ReactDOM.render(
    ReactComponent,
      DOMElement,
      [callback]
)

一句话概括:

渲染一个ReactComponent,将其作为DOMElementinnerHTML

记住两件事:

这个方法只会进行一次整体更新

第一次渲染后,会将DOMElementinnerHTMLReactComponent的实例所替换,之后的渲染,便采用高效的diff算法进行更新。

几个问题:

这个方法是同步的还是异步的?

这个方法有没有返回值?

callback函数,有参数吗?

来一起扯扯:

先看这个代码:

import React from "react";
import {findDOMNode, render} from "react-dom";

// 函数式组件一
const FieldInput = (props) => {
    return (
        
) } class App extends React.Component { constructor(props) { super(props) } render() { return (
The header
) } } console.log("%c begin render", "color:red") const baseComponent = render(, document.getElementById("root")) console.log(baseComponent) console.log("%c end render", "color:red")

结果呢,是这样的。不错,同步调用的。而且返回值就是我们的根组件的实例。

挺好的,可是,官方有声明:

所以嘞,我们应该避免使用这种方式获取根组件实例(一般也不会采用这种方法操作根组件实例,只需要知道有这么回事就好了)。

再看一下这段代码:

import React from "react";
import {findDOMNode, render} from "react-dom";

class App extends React.Component {
    constructor(props) {
        super(props)
    }
    render() {
        return (
            
test
) } } render(, document.getElementById("root"), (...args) => { console.log(args) // [] })

这个回调函数其实是没有参数的,但是,当render方法变成异步方法之后,说不定就会向其注入一些参数了。具体的,拭目以待。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/85176.html

相关文章

  • 【译】State and Lifecycle (State和生命周期)

    摘要:结果如下打开试试下一步,我们将把组件功能自己设置定时器并且能每秒更新。这是一个设置定时器的好地方注意我们是怎么保存定时器的。我们将在这个生命周期的函数方法中卸载掉定时器最后,我们会每一秒跑方法。 下面是react官方文档的个人翻译,如有翻译错误,请多多指出原文地址:https://facebook.github.io/re... Consider the ticking clock e...

    dadong 评论0 收藏0
  • 【译】渲染Elements

    摘要:注不做翻译是中最小的构建部件。在里渲染让我们看一下在下面有在你文件中无处不在的标签我们会把这元素成为元素因为的所有东西都会放在这个元素里面。通过方法,我们能吧渲染到我们根节点上。更新被渲染的是不可变的。 下面是react官方文档的个人翻译,如有翻译错误,请多多指出原文地址:https://facebook.github.io/re...特别感谢Hevaen,同时也向豪大React群所有...

    LoftySoul 评论0 收藏0
  • React

    摘要:语法是一种语法的拓展语言,在中官方也推荐使用描述用户界面,使用起来会比较快捷而且易读不是一门新的语言,可以理解为是一种语法糖,作用就是能够让我们更加直观的在中创建标签,最终还是会被编译为语法,例如我们看一段代码上面的语法最终会被编译为语法, Reatc JSX语法 jsx是一种JavaScript语法的拓展语言,在React中官方也推荐使用jsx描述用户界面,使用起来会比较快捷而且易读...

    techstay 评论0 收藏0
  • ReactDOM.render源码解析-1

    摘要:本文将对源码做一个初步解析。首先在方法中校验参数是否合法,然后调用在中,调用拿到了的一个实例,调用拿到了,用于注入到,和作为返回值,调用开始调度过程在中,首先清理了中的所有子节点,然后了一个并返回是如何调度的是一个什么样的类的操作是在哪里 初步看了react-dom这个包的一些源码,发现其比react包要复杂得多,react包中基本不存在跨包调用的情况,他所做的也仅仅是定义了React...

    _Zhao 评论0 收藏0
  • React源码系列一之createElement

    前言:使用react也有二年多了,一直停留在使用层次。虽然很多时候这样是够了。但是总觉得不深入理解其背后是的实现逻辑,很难体会框架的精髓。最近会写一些相关的一些文章,来记录学习的过程。 备注:react和react-dom源码版本为16.8.6 本文适合使用过React进行开发,并有一定经验的人阅读。 好了闲话少说,我们一起来看源码吧写过react知道,我们使用react编写代码都离不开webpa...

    Zhuxy 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<