代码大致如下,子组件有自己的状态但受父组件的控制,当父组件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>
}