useRef 解决 useCallback 的问题
思路:
- 为了避免子组件 child 在无效的重新渲染,必须保证父组件 渲染 时 handleSubmit 属性值不变;
- 在 handleSubmit 属性值不变的情况下,也要保证其能够访问到最新的 state。
原理:
- handleSubmit 由原来直接依赖 text 变成了依赖 textRef,因为每次 re-render 时 textRef 不变,所以 handleSubmit 不变;
- 每次 text 更新时都更新 textRef.current。这样虽然 handleSubmit 不变,但是通过 textRef 也是能够访问最新的值。
import React, { useState, useCallback, useEffect, useRef } from "react";
// 注意:Child 比较耗时记得使用`React.memo`优化下,要不然父组件优化也没用
const Child = React.memo(function (props) {
console.log("Render Child");
const { onClick } = props;
// 很重的组件,不优化会死的那种,真的会死人
useEffect(() => {
console.log("Render Child --- DONE");
});
return (
<div onClick={onClick}>
<p>很重的组件,不优化会死的那种</p>
</div>
);
});
// useCallback:由于 依赖时 是动态变化的,所以 handleSubmit 每次都会生成新方法
// export default function Index() {
// const [text, updateText] = useState("Initial value");
// const handleSubmit = useCallback(() => {
// console.log(`Text: ${text}`);
// }, [text]);
// return (
// <>
// <input value={text} onChange={(e) => updateText(e.target.value)} />
// <Child onClick={handleSubmit} />
// </>
// );
// }
// useRef解决方案
export default function Parent() {
const [text, updateText] = useState("Initial value");
const textRef = useRef(text);// 把 动态text 变成引用,由于memo进行浅比较,不会触发更新
const handleSubmit = useCallback(() => {
console.log(`Text: ${textRef.current}`);
}, []); // 不需要依赖项
useEffect(() => {
console.log("update text");
textRef.current = text;
}, [text]);
return (
<>
<input value={text} onChange={(e) => updateText(e.target.value)} />
<Child onClick={handleSubmit} />
</>
);
}