react re-render的解决方案

问题代码
import {
   Dispatch, FC, SetStateAction, useState} from 'react'

import './App.css'


const Child: FC<{
     m: number, setM: Dispatch<SetStateAction<number>>  }> = (props) => {
   
    const {
   m, setM  } = props
    return (
        <div>
            <button onClick={
   () => setM(m + 1)}>addM</button>
            <span>child</span>
            <span>{
   m}</span>
        </div>
    )
}
const App = () => {
   
    const [n, setN] = useState(0)
    const [m, setM] = useState(0)
    return (
        <div>
            <button onClick={
   () => setN(n + 1)}>addN</button>
            <span>father</span>
            <span>{
   n}</span>
            <div>
                <Child m={
   m} setM={
   setM}/>
            </div>

        </div>
    )
}

export default App
问题描述

上面这个组件现在存在的问题:
当我们在点击n+1时,会导致App组件重新渲染,然后Child组件虽然不依赖n,但是由于父组件re-render,他自己也会进行无效的re-render

解决方法一 使用Memo

为了减少这种无效的re-render,我们经常会使用memo()去包裹组件,配合useCallback缓存函数,useMemo缓存其他变量来达到缓存组件,减少无效更新的情况。

import {
   Dispatch, FC, memo, SetStateAction, useCallback, useState} from 'react'

import './App.css'


const _Child: FC<{
     m: number, setM: Dispatch<SetStateAction<number>>  }> = (props) => {
   
    const {
   m, setM  } = props
    console.log('child render')
    return (
        <div>
            <button onClick={
   () => setM(m + 1)}>addM</button>
            <span>child</span>
            <span>{
   m}</span>
        </div>
    )
}
const Child= memo(_Child)


const App = () => {
   
    const [n, setN] = useState(0)
    const [m, setM] = useState(0)
    return (
        <div>
            <button onClick={
   () => setN(n + 1)}>addN</button>
            <span>father</span>
            <span>{
   n}</span>
            <div>
                <Child m={
   m} setM={
   useCallback(setM, [])}/>
            </div>
        </div>
    )
}
解决方法二 向下移动state

这个解决方法其实就是将组件粒度变得更细。
将state下沉到与之相关的组件中去,也就是将与该状态相关的组件抽离成一个单独的组件。

import {
   useState} from 'react'

import './App.css'


const Child = () => {
   
    const [m, setM] = useState(0)
    return (
        <div>
            <button onClick={
   () => setM(m + 1)}>addM</button>
            <span>child</span>
            <span>{
   m}</span>
        </div>
    )
}

const Child2 = () => {
   
    const [n, setN] = useState(0)
    return (
        <>
            <button onClick={
   () => setN(n + 1)}>addN</button>
            <span>Child2</span>
            <span>{
   n}</span>
        </>
    )
}
const App = () => {
   
    return (
        <div>
            <div>
                <Child2/>
            </div>
            <div>
                <Child/>
            </div>

        </div>
    )
}

export default App



解决方法三 内容提升

像上面那种情况,组件可以单独抽离是因为知道Child组件不依赖n的状态 代码如下。
但是如果我们假设是App中的div依赖n呢。这种情况下其实Child组件依然不应该刷新

import {
   Dispatch, FC, SetStateAction, useState} from 'react'

import './App.css'


const Child: FC<{
     m: number, setM: Dispatch<SetStateAction<number>>  }> = (props) => {
   
    const {
   m, setM  } = props
    return (
        <div>
            <button onClick={
   () => setM(m + 1)}>addM</button>
            <span>child</span>
            <span>{
   m}</span>
        </div>
    )
}
const App = () => {
   
    const [n, setN] = useState(0)
    const [m, setM] = useState(0)
    return (
        <div class={
   n.toString()}>  //父组件依赖n
            <button onClick={
   () => setN(n + 1)}>addN</button>
            <span>father</span>
            <span>{
   n}</span>
            <div>
                <Child m={
   m} setM={
   setM}/>
            </div>

        </div>
    )
}

export default App

解决上面代码的问题

将于n相关的组件放到Father中,然后不相关的作为children传给Father组件。
这样在Father组件re-render的时候,由于App(父组件)中的组件没有变化,所以拿到的children依然是上一次的(没有发生变化的)所以children部分不会re-render。
这样就避免了无效的刷新

import {
   FC, HTMLAttributes, useState} from 'react';

export default function App() {
   
    return (
        <Father>
            <Child/>
        </Father>
    );
}

// 将内容提升到该父组件中
interface Props extends HTMLAttributes<HTMLDivElement>{
   }
const  Father:FC<Props>=({
    children})=> {
   
    const [n, setN] = useState(0)
    return (
        <div>
            <button onClick={
   () => setN(n + 1)}>addN</button>
            <span>father</span>
            <span>{
   n}</span>
            <div>
                {
   children}
            </div>

        </div>
    )
}

const Child = () => {
   
    const [m, setM] = useState(0)
    console.log("执行了")
    return (
        <div>
            <button onClick={
   () => setM(m + 1)}>addM</button>
            <span>child</span>
            <span>{
   m}</span>
        </div>
    )
}
解决方法四 内容集中
import {
   useState} from 'react'

import './App.css'


const App = () => {
   
    const [n, setN] = useState(0)
    const [m, setM] = useState(0)
    return (
        <div className={
   n.toString()}>
            <div>
                <button onClick={
   () => setN(n + 1)}>addN</button>
                <span>father</span>
                <span>{
   n}</span>
            </div>
            // 将内容提升到该父组件中
            <div>
                <button onClick={
   () => setM(m + 1)}>addM</button>
                <span>child</span>
                <span>{
   m}</span>
            </div>

        </div>
    )
}

export default App

相关推荐

  1. ReactNative实现 RSC Render 解决方案

    2023-12-11 18:08:01       136 阅读
  2. react re-render解决方案

    2023-12-11 18:08:01       59 阅读
  3. React中如何避免不必要render

    2023-12-11 18:08:01       57 阅读
  4. reactrender什么时候渲染?

    2023-12-11 18:08:01       53 阅读
  5. React render方法原理?在什么时候会被触发?

    2023-12-11 18:08:01       43 阅读
  6. 深入理解 React children props 和 render props

    2023-12-11 18:08:01       51 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2023-12-11 18:08:01       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2023-12-11 18:08:01       100 阅读
  3. 在Django里面运行非项目文件

    2023-12-11 18:08:01       82 阅读
  4. Python语言-面向对象

    2023-12-11 18:08:01       91 阅读

热门阅读

  1. golang游戏服务器 - tgf系列课程01

    2023-12-11 18:08:01       61 阅读
  2. GO设计模式——3、抽象工厂模式(创建型)

    2023-12-11 18:08:01       59 阅读
  3. Vue学习笔记-Vue3中setup函数注意点

    2023-12-11 18:08:01       60 阅读
  4. 风扭转对风力发电机的影响

    2023-12-11 18:08:01       57 阅读
  5. Linux下文本三剑客:grep、awk、sed之对比

    2023-12-11 18:08:01       61 阅读
  6. 力扣labuladong一刷day35天

    2023-12-11 18:08:01       43 阅读
  7. ABAP 选择屏幕创建按钮,并执行

    2023-12-11 18:08:01       50 阅读