问答

使用React hooks如何只让下面这段代码的子组件只render一次?

作者:admin 2021-04-22 我要评论

代码大致如下,子组件有自己的状态但受父组件的控制,当父组件count更新的时候,需要将子组件的number和父组件的count保持同步,但是使用useEffect和useMemo都会...

在说正事之前,我要推荐一个福利:你还在原价购买阿里云、腾讯云、华为云服务器吗?那太亏啦!来这里,新购、升级、续费都打折,能够为您省60%的钱呢!2核4G企业级云服务器低至69元/年,点击进去看看吧>>>)

代码大致如下,子组件有自己的状态但受父组件的控制,当父组件count更新的时候,需要将子组件的number和父组件的count保持同步,但是使用useEffect和useMemo都会让子组件render两次,有什么方法可以只render一次吗?

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

function A() {
  const [count, setCount] = useState(0)

  return <div>
    <p>我是父组件</p>
    <p>父组件的count是{count}</p>
    <button onClick={() => setCount(count + 1)}>click</button>
    <B count={count} />
  </div>
}

const B = React.memo(({count}: {count: number}) => {
  const [number, setNumber] = useState(0)
  // useEffect(() => {
  //   setNumber(count)
  // }, [count])

  useMemo(() => {
    setNumber(count)
  }, [count])

  console.log('子组件render')
  return <div>
    <p>我是子组件</p>
    <p>子组件的number是{number}</p>
    <button onClick={() => setNumber(number + 1)}>click</button>
  </div>
})

export default A
###

无法避免。但是可以跳过组件B的子组件重新渲染:

const B = React.memo(({count}) => {
  const [number, setNumber] = useState(0)
  const initCountRef = useRef(0);
  if(initCountRef.current !== count) {
    setNumber(count);
    initCountRef.current = count;
  }

  console.log('子组件render', number)
  return <div>
    <p>我是子组件</p>
    <p>子组件的number是{number}</p>
    <button onClick={() => setNumber(number + 1)}>click</button>
  </div>
})
###
function useCountSyncState(count: number) {
  const [_, update] = useState(0)
  const numberRef = useRef(0)

  // newValue 这个可以是个callback 做到与 setState一致,开发体验更好
  const setValue = useCallback((newValue: number) => {
    numberRef.current = newValue
    update(pre => pre + 1)
  }, [numberRef.current])

  useLayoutEffect(() => {
    numberRef.current = count
  }, [count])

  return [numberRef.current, setValue]
}

const B = React.memo(({count}: {count: number}) => {
  const [number, setNumber] = useCountSyncState(0, count)

  console.log('子组件render')
  return <div>
    <p>我是子组件</p>
    <p>子组件的number是{number}</p>
    <button onClick={() => setNumber(number + 1)}>click</button>
  </div>
})

使用自定义hook 模拟一下 setState行为,应该可以实现,题主也可以验证一下看看有没有坑点

###

不知道你为啥整这么复杂,就不能简单一点?

const B: React.FunctionComponent<{
    count: number
    setCount: (count: number) => void
}> = ({ count, setCount }) => {
    return <div>
        <p>我是子组件</p>
        <p>子组件的number是{count}</p>
        <button onClick={() => setCount(count + 1)}>click</button>
    </div> 
}
const A = () => {
    const [count, setCount] = useState(0)

    return <div>
        <p>我是父组件</p>
        <p>父组件的count是{count}</p>
        <button onClick={() => setCount(count + 1)}>click</button>
        <B count={count} setCount={setCount}/>
    </div>
}

版权声明:本文转载自网络,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。本站转载出于传播更多优秀技术知识之目的,如有侵权请联系QQ/微信:153890879删除

相关文章
  • 求助!Mysql workbench connections出

    求助!Mysql workbench connections出

  • c++ 的dll 转golang可以调用

    c++ 的dll 转golang可以调用

  • c++的 new int{10}  和 new int(10) 有

    c++的 new int{10} 和 new int(10) 有

  • Grafana MySQL为数据源时, 折线图无法

    Grafana MySQL为数据源时, 折线图无法

腾讯云代理商
海外云服务器