博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ReactDOM You Should
阅读量:7163 次
发布时间:2019-06-29

本文共 6749 字,大约阅读时间需要 22 分钟。

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。但是,对比之中你应该清楚两件事。

图片描述

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

  2. 如果组件的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方法变成异步方法之后,说不定就会向其注入一些参数了。具体的,拭目以待。

转载地址:http://tatwm.baihongyu.com/

你可能感兴趣的文章