复用组件
在协调阶段,组件复用的前提是必须同时满足三个条件:同一层级下、同一类型、同一个key值。所以我们要尽量保证这三者的稳定性
常见错误:key=Math.random() 常见不规范写法:key=index
减少组件的render
组件重新render会导致组件进入协调,协调的核心就是常说的vdom diff,所以协调本身就是比较耗时的算法,因此如果能减少协调,复用旧的fiber节点,那么肯定会加快渲染完成的速度。组件如果没有进入协调阶段,我们称为进入bailout阶段,意思就是组件退出更新。
让组件进入bailout阶段,有以下方法
shouldComponentUpdate:component类组件的一个生命周期,当用户定义这个函数并且返回fasle,则进入bailout阶段。PureComponent: react提供的封装 shouldComponentUpdate的类组件,更新前会自行浅比较新旧props与state是否改变,如果两者都没变,则进入bailout阶段。memo: 第二个参数可作为用户自定义,如果没有自定义则使用浅比较,比较组件更新前后的props是否相同,如果相同,则进入bailout阶段。
const ChildMemo = memo(
function Child({item}) {
console.log('memo funtion')
return <div>memo</div>
}
// 这里的arePropsEqual 是个函数
// , (pre, next) => {
// return pre.item === next.item
// }
)
附上源码部分
useMemo可以缓存参数,可以对比useCallback使用,useCallback(fn, deps)相当于useMemo(() => fn, deps)
const cachedValue = useMemo(calculateValue, dependencies)
const cachedFn = useCallback(fn, dependencies)
- Context:Context本身就是通过Provider传递的value变化,所有消费这个value的后代组件都要更新,因此应该精简使用Context。
如下面的例子,点击任何一个button,都会导致 UserName 和 UserAge重新渲染,这不太合理,因为 UserAge与appContextValue.name无关,UserName与appContextValue.age无关。
import React, { useState } from "react";
export default function App() {
const [appContextValue, setContextValue] = useState({
name: 'zzzzz',
age: 23
});
return (
<div>
<button
onClick={() => {
setContextValue({
...appContextValue,
age: appContextValue.age++,
});
}}
></button>
<button
onClick={() => {
setContextValue({
...appContextValue,
name: appContextValue.name + `age: ${appContextValue.age}`,
});
}}
></button>
<AppContext.Provider value={appContextValue}>
<UserName />
<UserAge />
</AppContext.Provider>
</div>
);
}