You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
constChildComponent=()=>{const[title,setTitle]=useState("");return<div>{title}</div>;};constMainComponent=()=>{// title 不应该定义在这里return(<><ChildComponent/><FooCompoent/></>);};
constComponentWithTitle=({ children })=>{const[title,setTitle]=useState("");// ...return(<divonClick={()=>{setTitle("xxx");}}>{/* children 不会触发渲染 */}{children}</div>)}constComponent=()=>{return(<ComponentWithTitle><ChildComponent/></ComponentWithTitle>)}
这样当setValue时 ComponentWithTitle 就会触发渲染,而传入的 children 组件并不会受到影响。
在 React 中渲染阶段有 initial render 初始化渲染和 re-render 重新渲染,了解是什么原因导致触发重新渲染比较重要,虽然整理时思路清晰,但在平时写代码的时候还是得想下如何合理划分组件才行。
触发 re-render 的原因
相关 state 定义在子组件中
基本的子组件用的 state 如果定义在父组件会触发同级组件 FooCompoent 重新渲染
避免在组件中创建组件
子组件不应该定义内部,否则每次父组件 re-render 都会将 ChildComponent 销毁再创建
将组件作为 children 传递或 props
当修改父组件的一些状态但不想影响子组件时,可以写一个新的组件,将子组件当作 ChildComponent 传递进这个新组件,并将状态修改加在这个新组件中。
例如下面例子中每次修改 title 就会触发 ChildComponet 渲染:
但实际上 ChildComponent 并不需要重新渲染,可以将 ChildComponent 当作一个 children:
这样当setValue时 ComponentWithTitle 就会触发渲染,而传入的 children 组件并不会受到影响。
除了当做 children 还可以当作 props 传入,也不会触发渲染:
React.memo
使用 React.memo 可以阻止组件重新渲染,除非组件的 props 发生了变化
如果被 memo 包裹的组件传入一个未被 memo 的组件则不起作用,对象类型会在每次父组件渲染时都会变化,进而引起子组件重新渲染,例如下面代码当 MainComponent 触发渲染时 MyAComponent 和 MyBComponent 都会触发渲染:
所以需要同样将 MyAComponent 和 MyBComponent 用 memo 包裹,这样 MainComponent 重新渲染时,MyAMemo 和 MyBMemo 就不会触发:
useMemo
将子组件的 props 用 usememo 包装是不能避免 ChildComponent 重新渲染的:
如果子组件被 React.memo 包装,那么子组件所有的引用类型值可以做缓存处理,否则 MainComponent 重新渲染时也会触发子组件渲染:
如果父组件的hooks依赖引用类型,也可以做 memo 处理否则每次都会触发 effect:
可以在组件内部用 useMemo 缓存子组件:
Context 引起的重新渲染
在父组件里定义了 context 时,当父组件重新渲染,所有 context 下的组件都会重新渲染,可以通过划分数据方法避免部分重新渲染:
当点击 setDataA 修改值时,Child2 组件不会触发重新渲染,当点击 setDataB 修改值时,Child1 组件不会触发重新渲染。
防抖和节流
可以利用 ahooks 的 useThrottleEffect 或 useDebounceEffect 代替 useEffect 减少多次触发渲染:
The text was updated successfully, but these errors were encountered: