React父子组件,父组件状态更新,子组件的渲染状况

目录

React.memo不包裹

React.memo包裹

传递一个简单数据类型

传递一个复杂数据类型

传递一个函数


React.memo不包裹

如果子组件没有使用React.memo包裹,则父组件中数据更新时,子组件会重新进行渲染

父组件:

import { useState } from 'react'
import Son from './Son'

export default function App() {
  const [num, setNum] = useState(100)

  return (
    <>
      <h2>App</h2>
      <button onClick={() => setNum(num + 1)}>num++ -- {num}</button>
      <Son></Son>
    </>
  )
}

子组件:

export default function Son() {
  console.log('子组件触发更新')

  return (
    <div>
      <h3>Son</h3>
    </div>
  )
}

会发现,在页面初始化加载的时候会触发一次。父组件里状态更新的时候也会触发一次

React.memo包裹

这里主要分析React.memo包裹的情况:

  • 正常的话,只有传值给子组件的值(也就是子组件props中的值)发生改变时才会触发子组件渲染

父组件:

import { useState } from 'react'
import Son from './Son'

export default function App() {
  const [num, setNum] = useState(100)

  return (
    <>
      <h2>App</h2>
      <button onClick={() => setNum(num + 1)}>num++ -- {num}</button>
      <Son></Son>
    </>
  )
}

子组件:

import React from 'react'

export default React.memo(function Son() {
  console.log('子组件触发更新')

  return (
    <div>
      <h3>Son</h3>
    </div>
  )
})

结果:

然后我们依次分析各种传值的情况

传递一个简单数据类型

    1. 传值给子组件一个简单数据类型的值:只有值改变的时候子组件才会重新渲染

父组件:

import { useState } from 'react'
import Son from './Son'

export default function App() {
  const [num, setNum] = useState(100)
  const count = 99

  return (
    <>
      <h2>App</h2>
      <button onClick={() => setNum(num + 1)}>num++ -- {num}</button>
      <Son count={count}></Son>
    </>
  )
}

子组件:

import React from 'react'

interface IProps {
  count: number
}

export default React.memo(function Son(props: IProps) {
  const { count } = props
  console.log('子组件触发更新')

  return (
    <div>
      <h3>Son</h3>
    </div>
  )
})

结果:

传递一个复杂数据类型

    2. 传值给子组件一个复杂数据类型的值:

  • 如果值使用useState包裹,则只有值改变的时候子组件才会重新渲染
  • 如果没有使用useState包裹,则不管值是否变化,只要父组件数据有变化,都会触发子组件重新渲染

不使用useState包裹

父组件:

import { useState } from 'react'
import Son from './Son'

export default function App() {
  const [num, setNum] = useState(100)
  const list = [1, 2, 3]

  return (
    <>
      <h2>App</h2>
      <button onClick={() => setNum(num + 1)}>num++ -- {num}</button>
      <Son list={list}></Son>
    </>
  )
}

子组件:

import React from 'react'

interface IProps {
  list: number[]
}

export default React.memo(function Son(props: IProps) {
  const { list } = props
  console.log('子组件触发更新')

  return (
    <div>
      <h3>Son</h3>
    </div>
  )
})

结果:

但是这显然不是我们想要的结果,我们使用React.memo包裹子组件,肯定是希望子组件接收的props值发生改变的时候才重新渲染子组件。如果要改善上面的情况,则就需要useMemo包裹下值(useMemo会缓存函数执行之后的值,只要参数2中的依赖项不发生改变,就不会触发参数1的回调函数)或者useState包裹下值

父组件:

import { useMemo, useState } from 'react'
import Son from './Son'

export default function App() {
  const [num, setNum] = useState(100)
  const list = useMemo(() => [1, 2, 3], [])

  return (
    <>
      <h2>App</h2>
      <button onClick={() => setNum(num + 1)}>num++ -- {num}</button>
      <Son list={list}></Son>
    </>
  )
}

子组件:

import React from 'react'

interface IProps {
  list: number[]
}

export default React.memo(function Son(props: IProps) {
  const { list } = props
  console.log('子组件触发更新')

  return (
    <div>
      <h3>Son</h3>
    </div>
  )
})

结果:

使用useState包裹

父组件:

import { useState } from 'react'
import Son from './Son'

export default function App() {
  const [num, setNum] = useState(100)
  const [list, setList] = useState([1, 2, 3])

  return (
    <>
      <h2>App</h2>
      <button onClick={() => setNum(num + 1)}>num++ -- {num}</button>
      <button onClick={() => setList([...list, 99])}>
        listChange -- {list}
      </button>
      <Son list={list}></Son>
    </>
  )
}

子组件:

import React from 'react'

interface IProps {
  list: Array<number>
}

export default React.memo(function Son(props: IProps) {
  const { list } = props
  console.log('子组件触发更新')

  return (
    <div>
      <h3>Son</h3>
    </div>
  )
})

结果:

传递一个函数

    3. 传值给子组件一个函数:不管函数有没有改变,只要父组件数据状态改变,都会触发子组件重新渲染

父组件:

import { useState } from 'react'
import Son from './Son'

export default function App() {
  const [num, setNum] = useState(100)
  const fn = () => {
    console.log('函数执行')
  }

  return (
    <>
      <h2>App</h2>
      <button onClick={() => setNum(num + 1)}>num++ -- {num}</button>
      <Son fn={fn}></Son>
    </>
  )
}

子组件:

import React from 'react'

interface IProps {
  fn: () => void
}

export default React.memo(function Son(props: IProps) {
  const { fn } = props
  console.log('子组件触发更新')

  return (
    <div>
      <h3>Son</h3>
    </div>
  )
})

结果:

同样的,我们使用React.memo包裹子组件,肯定也是希望子组件接收的props值发生改变的时候才重新渲染子组件。如果要改善上面的情况,则就需要useMemo包裹下函数(useMemo会缓存函数执行之后的值,只要参数2中的依赖项不发生改变,就不会触发参数1的回调函数)或者useCallback包裹下函数

父组件:

import { useMemo, useState } from 'react'
import Son from './Son'

export default function App() {
  const [num, setNum] = useState(100)
  const fn = useMemo(() => {
    return () => {
      console.log('函数执行')
    }
  }, [])

  return (
    <>
      <h2>App</h2>
      <button onClick={() => setNum(num + 1)}>num++ -- {num}</button>
      <Son fn={fn}></Son>
    </>
  )
}

子组件:

import React from 'react'

interface IProps {
  fn: () => void
}

export default React.memo(function Son(props: IProps) {
  const { fn } = props
  console.log('子组件触发更新')

  return (
    <div>
      <h3>Son</h3>
    </div>
  )
})

结果:

但是上面使用useMemo,还要return一个函数,写起来很臃肿,就可以使用useCallback这个hook来进行优化,效果是一样的。只需要改变下父组件代码即可

import { useCallback, useState } from 'react'
import Son from './Son'

export default function App() {
  const [num, setNum] = useState(100)
  const fn = useCallback(() => console.log('函数执行'), [])

  return (
    <>
      <h2>App</h2>
      <button onClick={() => setNum(num + 1)}>num++ -- {num}</button>
      <Son fn={fn}></Son>
    </>
  )
}

结果跟上面一样:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值