场景1- 演示一个子组件更新
父组件中一个输入框, 输入值,父组件更新, 同时引入子组件,但子组件也会跟着更新
import React, { useState } from "react";
import ReactDOM from "react-dom";
// 子组件
function Bpp() {
console.log("%c Bpp render", "color:green");
return (
<>
<div>Bpp组件渲染</div>
</>
);
}
// 父组件
function App() {
const [val, setVal] = useState(100);
console.log("%c App组件 render", "color:red");
return (
<div>
<span>App组件渲染</span>
<input value={val} onChange={(e) => setVal(e.target.value)} />
<hr />
<Bpp />
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
此时,子组件并没有任何依赖,但是却产生了不必要的更新, 即还可以再优化下性能
1.1 解决这种子组件的不必要更新
把子组件 通过 memo()包裹
// 子组件
function Bpp() {
console.log("%c Bpp render", "color:green");
return (
<>
<div>Bpp组件渲染</div>
</>
);
}
// 包裹一下,返回一个组件
Bpp = React.memo(Bpp);
// 父组件
function App() {
const [val, setVal] = useState(100);
console.log("%c App组件 render", "color:red");
return (
<div>
<span>App组件渲染</span>
<input value={val} onChange={(e) => setVal(e.target.value)} />
<hr />
<Bpp />
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
此时就只渲染父组件了
场景2- 父组件给子组件传入方法,引起的不必要更新
只要将父组件的方法传给子组件, 不管子组件用不用, 或者父组件的传入的这个方法 是不是又更新操作,都会触发子组件的更新
// 子组件
function Bpp() {
console.log("%c Bpp render", "color:green");
return (
<>
<div>Bpp组件渲染</div>
</>
);
}
// 包裹一下,返回一个组件
Bpp = React.memo(Bpp);
// 父组件
function App() {
const [name, setName] = useState("hello world");
console.log("%c App组件 render", "color:red");
// 父组件的方法,传给子组件
const handler = () => {
console.log(10);
};
return (
<div>
<span>App组件渲染</span>
<input value={name} onChange={(e) => setName(e.target.value)} />
<hr />
{/* 将方法传给子组件 */}
<Bpp clickHandler={handler} />
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
此情况下,也会一直触发更新操作
2.1 使用 useCallback 解决上述的渲染问题
在父组件中使用 useCallback 包裹要触发的函数,同样的第二个参数就是依赖项, 依赖项变化,也是会触发更新
function App() {
const [name, setName] = useState("hello");
console.log("%c App组件 render", "color:red");
// useCallback(_, []), 第二个参数还是 依赖项
const handler = useCallback(() => {
console.log(10);
}, []);
return (
<div>
<span>App组件渲染</span>
<input value={name} onChange={(e) => setName(e.target.value)} />
<hr />
{/* 将方法传给子组件 */}
<Bpp clickHandler={handler} />
</div>
);
}
场景3-, 父组件的某个值和方法都传给子组件
描述场景: 对单一基本数据类型再进行一次包装, 将它作为某个新对象的某个属性的值
// 子组件
function Bpp(props) {
console.log("%c Bpp render", "color:green");
return (
<>
<button onClick={props.click}>Bpp组件渲染</button>
</>
);
}
// 包裹一下,返回一个组件
Bpp = React.memo(Bpp);
// 父组件
function App() {
const [num, setNum] = useState(1);
const [name, setName] = useState("jklov");
console.log("%c App组件 render", "color:red");
// 父组件的方法
const clickHandler = useCallback(() => {
setNum(num + 1);
}, []);
// 对 num 包一层
let data = { num };
// let data = useMemo(() => ({ num }), []);
return (
<div>
<span>App组件渲染</span>
<input value={name} onChange={(e) => setName(e.target.value)} />
<hr />
{/* 将方法传给子组件 */}
<Bpp data={data} click={clickHandler} />
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
依旧触发子组件的更新
使用 useMomo 包裹一下
//... 略
let data = useMemo(() => ({ num }), []);
// ...略
实现原理。。。后续补。。。