「React进阶」 React全部api解读+基础实践大全(夯实基础2万字总结) (React DOM)

简介: 一份不错的 React 学习指南

接下来,我们来一起研究react-dom中比较重要的api

react-dom.jpg

render

render 是我们最常用的react-domapi,用于渲染一个react元素,一般react项目我们都用它,渲染根部容器app

ReactDOM.render(element, container[, callback])

使用

ReactDOM.render(
    < App / >,
    document.getElementById('app')
)

ReactDOM.render会控制container容器节点里的内容,但是不会修改容器节点本身。

hydrate

服务端渲染用hydrate。用法与 render() 相同,但它用于在 ReactDOMServer 渲染的容器中对 HTML 的内容进行 hydrate 操作。

ReactDOM.hydrate(element, container[, callback])

createPortal

Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案。createPortal 可以把当前组件或 element 元素的子节点,渲染到组件之外的其他地方。

那么具体应用到什么场景呢?

比如一些全局的弹窗组件model,<Model/>组件一般都写在我们的组件内部,倒是真正挂载的dom,都是在外层容器,比如body上。此时就很适合createPortalAPI。

createPortal接受两个参数:

ReactDOM.createPortal(child, container)

第一个: child 是任何可渲染的 React 子元素
第二个: container是一个 DOM 元素。

接下来我们实践一下:

function WrapComponent({
   
    children }){
   
   
    const domRef = useRef(null)
    const [ PortalComponent, setPortalComponent ] = useState(null)
    React.useEffect(()=>{
   
   
        setPortalComponent( ReactDOM.createPortal(children,domRef.current) )
    },[])
    return <div> 
        <div className="container" ref={
   
    domRef } ></div>
        {
   
    PortalComponent }
     </div>
}

class Index extends React.Component{
   
   
    render(){
   
   
        return <div style={
   
   {
   
    marginTop:'50px' }} >
             <WrapComponent>
               <div  >hello,world</div>
            </WrapComponent>
        </div>
    }
}

效果

createPortal.jpg

我们可以看到,我们children实际在container 之外挂载的,但是已经被createPortal渲染到container中。

unstable_batchedUpdates

react-legacy模式下,对于事件,react事件有批量更新来处理功能,但是这一些非常规的事件中,批量更新功能会被打破。所以我们可以用react-dom中提供的unstable_batchedUpdates 来进行批量更新。

一次点击实现的批量更新

class Index extends React.Component{
   
   
    constructor(props){
   
   
       super(props)
       this.state={
   
   
           numer:1,
       }
    }
    handerClick=()=>{
   
   
        this.setState({
   
    numer : this.state.numer + 1 })
        console.log(this.state.numer)
        this.setState({
   
    numer : this.state.numer + 1 })
        console.log(this.state.numer)
        this.setState({
   
    numer : this.state.numer + 1 })
        console.log(this.state.numer)
    }
    render(){
   
   
        return <div  style={
   
   {
   
    marginTop:'50px' }} > 
            <button onClick={
   
    this.handerClick } >click me</button>
        </div>
    }
}

效果

batch1.jpg

渲染次数一次。

批量更新条件被打破

 handerClick=()=>{
   
   
    Promise.resolve().then(()=>{
   
   
        this.setState({
   
    numer : this.state.numer + 1 })
        console.log(this.state.numer)
        this.setState({
   
    numer : this.state.numer + 1 })
        console.log(this.state.numer)
        this.setState({
   
    numer : this.state.numer + 1 })
        console.log(this.state.numer)
    })
  }

效果

batch2.jpg

渲染次数三次。

unstable_batchedUpdate助力

 handerClick=()=>{
   
   
        Promise.resolve().then(()=>{
   
   
            ReactDOM.unstable_batchedUpdates(()=>{
   
   
                this.setState({
   
    numer : this.state.numer + 1 })
                console.log(this.state.numer)
                this.setState({
   
    numer : this.state.numer + 1 })
                console.log(this.state.numer)
                this.setState({
   
    numer : this.state.numer + 1 })
                console.log(this.state.numer)
            }) 
        })
    }

渲染次数一次,完美解决批量更新问题。

flushSync

flushSync 可以将回调函数中的更新任务,放在一个较高的优先级中。我们知道react设定了很多不同优先级的更新任务。如果一次更新任务在flushSync回调函数内部,那么将获得一个较高优先级的更新。比如

ReactDOM.flushSync(()=>{
   
   
    /* 此次更新将设置一个较高优先级的更新 */
    this.setState({
   
    name: 'alien'  })
})

为了让大家理解flushSync,我这里做一个demo奉上,

/* flushSync */
import ReactDOM from 'react-dom'
class Index extends React.Component{
   
   
    state={
   
    number:0 }
    handerClick=()=>{
   
   
        setTimeout(()=>{
   
   
            this.setState({
   
    number: 1  })
        })
        this.setState({
   
    number: 2  })
        ReactDOM.flushSync(()=>{
   
   
            this.setState({
   
    number: 3  })
        })
        this.setState({
   
    number: 4  })
    }
    render(){
   
   
        const {
   
    number } = this.state
        console.log(number) // 打印什么??
        return <div>
            <div>{
   
    number }</div>
            <button onClick={
   
   this.handerClick} >测试flushSync</button>
        </div>
    }
}

先不看答案,点击一下按钮,打印什么呢?

我们来点击一下看看

flushSync.gif

打印 0 3 4 1 ,相信不难理解为什么这么打印了。

  • 首先 flushSync this.setState({ number: 3 })设定了一个高优先级的更新,所以3 先被打印
  • 2 4 被批量更新为 4

相信这个demo让我们更深入了解了flushSync

findDOMNode

findDOMNode用于访问组件DOM元素节点,react推荐使用ref模式,不期望使用findDOMNode

ReactDOM.findDOMNode(component)

注意的是:

  • 1 findDOMNode只能用在已经挂载的组件上。

  • 2 如果组件渲染内容为 null 或者是 false,那么 findDOMNode返回值也是 null

  • 3 findDOMNode 不能用于函数组件。

接下来让我们看一下,findDOMNode具体怎么使用的:

class Index extends React.Component{
   
   
    handerFindDom=()=>{
   
   
        console.log(ReactDOM.findDOMNode(this))
    }
    render(){
   
   
        return <div style={
   
   {
   
    marginTop:'100px' }} >
            <div>hello,world</div>
            <button onClick={
   
    this.handerFindDom } >获取容器dom</button>
        </div>
    }
}

效果:

findNodedom.gif

我们完全可以将外层容器用ref来标记,获取捕获原生的dom节点。

unmountComponentAtNode

DOM 中卸载组件,会将其事件处理器和 state 一并清除。 如果指定容器上没有对应已挂载的组件,这个函数什么也不会做。如果组件被移除将会返回 true ,如果没有组件可被移除将会返回 false

我们来简单举例看看unmountComponentAtNode如何使用?

function Text(){
   
   
    return <div>hello,world</div>
}

class Index extends React.Component{
   
   
    node = null
    constructor(props){
   
   
       super(props)
       this.state={
   
   
           numer:1,
       }
    }
    componentDidMount(){
   
   
        /*  组件初始化的时候,创建一个 container 容器 */
        ReactDOM.render(<Text/> , this.node )
    }
    handerClick=()=>{
   
   
       /* 点击卸载容器 */ 
       const state =  ReactDOM.unmountComponentAtNode(this.node)
       console.log(state)
    }
    render(){
   
   
        return <div  style={
   
   {
   
    marginTop:'50px' }}  > 
             <div ref={
   
    ( node ) => this.node = node  }  ></div>  
            <button onClick={
   
    this.handerClick } >click me</button>
        </div>
    }
}

效果

unmounted.gif

本文通过react组件层面,工具层面,hooks层面,react-dom了解了api的用法,希望看完的同学,能够对着文章中的demo自己敲一遍,到头来会发现自己成长不少。

最后, 送人玫瑰,手留余香,觉得有收获的朋友可以给笔者点赞,关注一波 ,陆续更新前端超硬核文章。

提前透漏:接下来会出一部揭秘react事件系统的文章。

感兴趣的同学请关注公众号 前端Sharing 持续推送优质好文

往期react文章

文章中,对于其他没有讲到的react-hooks,建议大家看react-hooks三部曲。

react-hooks三部曲

react进阶系列

react源码系列

开源项目系列

参考文档

react中文文档

相关文章
|
1月前
|
前端开发 JavaScript API
基于React的简易REST API客户端设计与实现
基于React的简易REST API客户端设计与实现
21 3
|
1月前
|
JavaScript 前端开发 API
深入浅出:Vue 3 Composition API 的魅力与实践
【2月更文挑战第13天】 本文将探索 Vue 3 的核心特性之一——Composition API。通过对比 Options API,本文旨在揭示 Composition API 如何提高代码的组织性和可复用性,并通过实际案例展示其在现代前端开发中的应用。不同于传统的技术文章摘要,我们将通过一个具体的开发场景,引领读者步入 Composition API 的世界,展现它如何优雅地解决复杂组件逻辑的管理问题,从而激发读者探索和运用 Vue 3 新特性的热情。
23 1
|
2月前
|
数据采集 监控 算法
利用大数据和API优化电商决策:商品性能分析实践
在数据驱动的电子商务时代,大数据分析已成为企业提升运营效率、增强市场竞争力的关键工具。通过精确收集和分析商品性能数据,企业能够洞察市场趋势,实现库存优化,提升顾客满意度,并显著增加销售额。本文将探讨如何通过API收集商品数据,并将这些数据转化为对电商平台有价值的洞察。
|
2月前
|
人工智能 NoSQL Serverless
基于函数计算3.0 Stable Diffusion Serverless API 的AI艺术字头像生成应用搭建与实践的报告
本文主要分享了自己基于函数计算3.0 Stable Diffusion Serverless API 的AI艺术字头像生成应用搭建与实践的报告
469 6
基于函数计算3.0 Stable Diffusion Serverless API 的AI艺术字头像生成应用搭建与实践的报告
|
1月前
|
JavaScript 前端开发 算法
js开发:请解释什么是虚拟DOM(virtual DOM),以及它在React中的应用。
虚拟DOM是React等前端框架的关键技术,它以轻量级JavaScript对象树形式抽象表示实际DOM。当状态改变,React不直接操作DOM,而是先构建新虚拟DOM树。通过高效diff算法比较新旧树,找到最小变更集,仅更新必要部分,提高DOM操作效率,降低性能损耗。虚拟DOM的抽象特性还支持跨平台应用,如React Native。总之,虚拟DOM优化了状态变化时的DOM更新,提升性能和用户体验。
24 0
|
3天前
|
前端开发 JavaScript API
React的Context API:全局状态管理的利器
【4月更文挑战第25天】React的Context API解决了深层组件间状态共享的难题,提供全局状态管理方案。通过`Provider`和`Consumer`组件,或结合`useContext` Hook,实现状态在组件树中的传递。最佳实践包括避免过度使用,分离逻辑,以及在必要时与Redux或MobX结合。Context API简化了数据传递,但需谨慎使用以保持代码清晰。
|
17天前
|
JavaScript 前端开发
|
29天前
|
XML JSON 安全
谈谈你对RESTful API设计的理解和实践。
RESTful API是基于HTTP协议的接口设计,通过URI标识资源,利用GET、POST、PUT、DELETE等方法操作资源。设计注重无状态、一致性、分层、错误处理、版本控制、文档、安全和测试,确保易用、可扩展和安全。例如,`/users/{id}`用于用户管理,使用JSON或XML交换数据,提升系统互操作性和可维护性。
18 4
|
1月前
|
消息中间件 缓存 API
微服务架构下的API网关性能优化实践
在现代的软件开发中,微服务架构因其灵活性和可扩展性被广泛采用。随着服务的细分与增多,API网关作为微服务架构中的关键组件,承担着请求路由、负载均衡、权限校验等重要职责。然而,随着流量的增长和业务复杂度的提升,API网关很容易成为性能瓶颈。本文将深入探讨API网关在微服务环境中的性能优化策略,包括缓存机制、连接池管理、异步处理等方面的具体实现,旨在为开发者提供实用的性能提升指导。
|
1月前
|
缓存 负载均衡 监控
构建高效微服务架构:API网关的作用与实践
【2月更文挑战第31天】 在当今的软件开发领域,微服务架构已成为实现系统高度模块化和易于扩展的首选方法。然而,随着微服务数量的增加,确保通信效率和管理一致性变得尤为重要。本文将探讨API网关在微服务架构中的核心角色,包括其在请求路由、安全性、负载均衡以及聚合功能方面的重要性。我们将通过具体案例分析,展示如何利用API网关优化后端服务,并讨论实施过程中的最佳实践和常见挑战。