React.memo和useMemo的区别及使用
发现问题大家在使用hook进行开发的时候有没有遇到过以下的情况:当我set某一个值的时候,有好多不相关的值都重新进行了计算,当代码量较小的时候可能不明显,但是长此以往会让页面越来越卡。父组件的某个值更新了,但是某些并没有引用这个值的子组件竟然也更新了。以上的两种情况如果一直放任不管的话,随着代码的累计,页面的性能就会越来越差。当用class组件的时候我们可以通过PureComponent或者生命周
发现问题
大家在使用hook进行开发的时候有没有遇到过以下的情况:
- 当我set某一个值的时候,有好多不相关的值都重新进行了计算,当代码量较小的时候可能不明显,但是长此以往会让页面越来越卡。
- 父组件的某个值更新了,但是某些并没有引用这个值的子组件竟然也更新了。
以上的两种情况如果一直放任不管的话,随着代码的累计,页面的性能就会越来越差。当用class组件的时候我们可以通过PureComponent或者生命周期中的shouldComponentUpdate方法来进行优化,但是对于hooks要怎么做呢?
hooks性能优化
在我们编写hook的时候可以通过React.memo和useMemo进行性能的优化。至于他们之间的区别大家可以跟着我的代码往下走。
使用useMemo进行优化
App.tsx:
function App() {
const [num, setNum] = useState(0);
const [name, setName] = useState('mx');
useEffect(() => {
setTimeout(() => {
setName('xx');
}, 2000)
}, [])
const memoVal = useMemo(() => {
console.log('useMemo内部运行了,num值是:', num);
return num + 1;
}, [num]);
console.log('memo值是:', memoVal);
console.log('---------------------------------------父组件运行分割线---------------------------------------------')
return (
<div className="App">
</div>
);
}
export default App;
这个组件的最终输出是:
在这里我们可以看到,尽管我们调用了setName,但是memo内部的函数并没有运行,也就是说只有num改变的时候才会重新计算memoVal的值。
使用React.memo进行优化
增加了一个Children.tsx
const Children = (props:any) => {
console.log('children运行了,对应的props是:',props);
console.log('--------------------------------子组件运行分割线----------------------------------')
return <div>children</div>
}
export default Children;
同时在App.tsx中调用该组件
// 省略之前代码
return (
<div className="App">
<Children num={num} />
</div>
);
此时的输出是:
我们明明只调用了setName,child也不需要name项,但是child还是进行了一次重新渲染,这就会造成不必要的性能损耗。这个时候React.memo就派上用场了。只需要对child进行一个小小的改动:
import React, { memo } from "react";
const Children = (props:any) => {
console.log('children运行了,对应的props是:',props);
console.log('--------------------------------子组件运行分割线----------------------------------')
return <div>children</div>
}
export default memo(Children);// 增加memo
此时你就会发现setName的时候children就不会再次运行。
React.memo的另一种情况
当num是对象的时候。
const [num, setNum] = useState({});
.
.
.
// 在某处业务代码上
setNum({});
这个时候我们会发现child组件又重新运行了一次,虽然对象的内容都是一样的。
这种情况下我们就需要对child做进一步处理:
export default memo(Children, (props, nextProps) => {
// 此处的逻辑可以根据你的业务自己code
return JSON.stringify(props) === JSON.stringify(nextProps)
});
memo的第二个参数就是对组件的入参前后进行对比,通过返回的布尔值来进行判断是否重新渲染。
个人建议这个参数要慎用,因为有些时候进行深度对比的开销有可能比重新渲染视图要高。
总结
hook中的性能优化主要有useMemo和React.memo。其中React.memo在没有第二的参数的时候相当于class中的PureComponent,当增加了第二个参数的时候相当于声明周期中的shouldComponentUpdate,但是可以明显感觉到hook的使用要更加的简单和灵活。
useMemo则是hook对比class一个显著的优势,因为通过useMemo我们可以进行更加细粒度的性能优化,这是class难以实现的。
更多推荐
所有评论(0)