类和函数中组件更新渲染的坑

10 篇文章 0 订阅
10 篇文章 0 订阅

在类组件每一次重新渲染时,会执行一遍 render() 内的代码

在函数式组件每一次重新渲染时,会重新执行一遍函数组件内的所有代码

且组件内声明的语句有一个特色:在不同的生命周期下,声明的同名变量在不同的生命周期下,在 react 看来是不同的变量,这点需要在组件更新时关注


如下面的例子代码:

类组件和函数式都是同一个作用:更新的时候添加一个点击事件,通过更改鼠标坐标并点击更改state从而发生更新【添加事件函数addEventListener() 对于完全相等的事件函数不会多次添加】

类组件的效果:每次更新时点击事件不会发生叠加,即如果点击三次,则再点击时只会打印一条 Class_inner

函数式组件的效果:每次更新时点击事件会发生点击,即如果点击三次,再次点击时会不止打印一条 Fun_inner,说明此时绑定的事件有多个,多个事件同时生效打印了多次

import React, { Component } from 'react'

export default class TestDemo extends Component {
    constructor() {
        super()
        this.state = {
            staus:true,
            positionX:0
        }
    }

    updataMouse = (e) => {
        console.log('Class_inner')	
        this.setState({
            positionX:e.clientX
        })
    }

    componentDidMount() {
        document.addEventListener('click', this.updataMouse)
    }

    componentDidUpdate() {
        document.addEventListener('click', this.updataMouse)
    }

    render() {
        return (
            <div></div>
        )
    }
}
import React, {useState, useEffect} from 'react'

export default function FunDemo() {
    const [staus, setStaus] = useState(true)
    const [positionX, setPositionX] = useState(0)

	const updataMouse = (e) => {
		console.log('Fun_inner')	
		setPositionX(e.clientX)
	}
    
    useEffect(() => {
        document.addEventListener('click', updataMouse)
    })

    return (
        <div></div>
    )
}

这是因为函数式组件的 updataMouse 被多次声明的原因,改写代码成下面,发现只有 updataMouse2 函数会出现事件叠加的现象,而 updataMouse1 事件无论组件更新了多少次都只会打印一条信息

说明了只有函数式组件内的代码在更新渲染时会被重新执行,声明了多次 updataMouse2 函数,且不同生命周期内的同名函数实际上在 react 看来是不同的,因此会多次绑定,因此最终就会产生事件叠加的效果

【class组件更新时只会执行render内的方法,因此更新时不会重新声明事件函数】

import React, {useState, useEffect} from 'react'
  
const updataMouse1 = (e) => {
    console.log('inner1')	
}

export default function FunDemo() {
    const [staus, setStaus] = useState(true)
    const [positionX, setPositionX] = useState(0)
  
    const updataMouse2 = (e) => {
        console.log('inner2')
        setPositionX(e.clientX)	 
    }

    useEffect(() => {
        document.addEventListener('click', updataMouse1)
        document.addEventListener('click', updataMouse2)
    })

    return (
        <div></div>
    )
}

不同声明周期下声明的同名变量会被 react 看做是不同的变量,如果该变量没有被继续引用则会被当垃圾清理,但是如果保持对这些变量的引用(往往都是函数调用),就像使用闭包没有及时断开引用一样,会让这些变量无法被清理,因此就会造成了事件叠加,需要手动地将这些引用及时清理掉

import React, {useState, useEffect} from 'react'

export default function FunDemo() {
    const [staus, setStaus] = useState(true)
    const [positionX, setPositionX] = useState(0)

	const updataMouse = (e) => {
		console.log('Fun_inner')	
		setPositionX(e.clientX)
	}
    
    useEffect(() => {
        document.addEventListener('click', updataMouse)
        return () => {
            removeEventListener('click', updataMouse)
        }
    })

    return (
        <div></div>
    )
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值