React性能优化-PureComponent、React.memo、useMemo、useCallback

参考官网链接:https://zh-hans.reactjs.org/docs/react-api.html#overview

React.PureComponent

用在class组件中用:

React.PureComponent 与 React.Component 很相似。两者的区别在于 React.Component 并未实现 shouldComponentUpdate(),而 React.PureComponent 中以浅层对比 prop 和 state 的方式来实现了该函数。

如果赋予 React 组件相同的 props 和 state,render() 函数会渲染相同的内容,那么在某些情况下使用 React.PureComponent 可提高性能。

React.memo()

用在函数组件中用:

如果你的组件在相同 props 的情况下渲染相同的结果,那么你可以通过将其包装在 React.memo 中调用,以此通过记忆组件渲染结果的方式来提高组件的性能表现。这意味着在这种情况下,React 将跳过渲染组件的操作并直接复用最近一次渲染的结果。

React.memo 仅检查 props 变更。如果函数组件被 React.memo 包裹,且其实现中拥有 useState,useReducer 或 useContext 的 Hook,当 context 发生变化时,它仍会重新渲染。

默认情况下其只会对复杂对象做浅层对比,如果你想要控制对比过程,那么请将自定义的比较函数通过第二个参数传入来实现。

性能优化相关的hook

useCallback和useMemo

1. useMemo

返回一个 memoized 值 。

把“创建”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。

记住,传入 useMemo 的函数会在 渲染期间 执行。请不要在这个函数内部执行与渲染无关的操作,诸如副作用这类的操作属于 useEffect 的适用范畴,而不是 useMemo。

如果没有提供依赖项数组,useMemo 在每次渲染时都会计算新的值。

	const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

举例1:

import React, { useState, useMemo } from "react";
export default function UseMemoPage(props) {
	const [count, setCount] = useState(0);
	const expensive = useMemo(() => {
		console.log("compute");
		let sum = 0;
		for (let i=0; i<count; i++) {
			sum+=i;
		}
		return sum;
		//只有count变化,这⾥才重新执⾏
	},[count]);
const [value, setValue] = useState("");
return (
		<div>
			<h3>UseMemoPage</h3>
			<p>expensive:{expensive}</p>
			<p>{count}</p>
			<button onClick={() => setCount(count + 1)}>add</button>
			<input value={value} onChange={event => setValue(event.target.value)} />
		</div>
	);
}

举例2:避免子组件重复渲染

import React, { useState, memo, useMemo } from 'react';

const HYInfo = memo((props) => {
  console.log("HYInfo重新渲染");
  return <h2>名字: {props.info.name} 年龄: {props.info.age}</h2>
});

export default function MemoHookDemo02() {
  console.log("MemoHookDemo02重新渲染");
  const [show, setShow] = useState(true);

  // const info = { name: "xiaoming", age: 18 };
  const info = useMemo(() => {
    return { name: "xiaoming", age: 18 };
  }, []);

  return (
    <div>
      <HYInfo info={info} />
      <button onClick={e => setShow(!show)}>show切换</button>
    </div>
  )
}
2. useCallback

返回一个 memoized 的回调函数 。

在这里插入图片描述

	useCallback(fn, deps) 相当于 useMemo(() => fn, deps)
import React, { useState, useCallback, PureComponent } from "react";
export default function UseCallbackPage(props) {
	const [count, setCount] = useState(0);
	const addClick = useCallback(() => {
	let sum=0;
	for (let i=0; i<count; i++) {
		sum+=i;
	}
	return sum;
}, [count]);
const [value, setValue] = useState("");
return (
		<div>
			<h3>UseCallbackPage</h3>
			<p>{count}</p>
			<button onClick={() => setCount(count + 1)}>add</button>
			<input value={value} onChange={event => setValue(event.target.value)} />
			<Child addClick={addClick} />
		</div>
	);
}
class Child extends PureComponent {
	render() {
		console.log("child render");
		const { addClick } = this.props;
		return (
			<div>
				<h3>Child</h3>
				<button onClick={() => console.log(addClick())}>add</button>
			</div>
			);
		}
}

useCallback
不能进行的性能优化:

import React, {useState, useCallback, useMemo} from 'react'

export default function CallbackHookDemo01() {
  const [count, setCount] = useState(0);

  const increment1 = () => {
    console.log("执行increment1函数");
    setCount(count + 1);
  }

  const increment2 = useCallback(() => {
    console.log("执行increment2函数");
    setCount(count + 1);
  }, [count]);
  return (
    <div>
      <h2>CallbackHookDemo01: {count}</h2>
      <button onClick={increment1}>+1</button>
      <button onClick={increment2}>+1</button>
    </div>
  )
}

可以进行性能优化场景:

import React, {useState, useCallback, memo} from 'react';
const HYButton = memo((props) => {
  console.log("HYButton重新渲染: " + props.title);
  return <button onClick={props.increment}>HYButton +1</button>
});

export default function CallbackHookDemo02() {
  console.log("CallbackHookDemo02重新渲染");
  const [count, setCount] = useState(0);
  const [show, setShow] = useState(true);
  const increment1 = () => {
    console.log("执行increment1函数");
    setCount(count + 1);
  }
  const increment2 = useCallback(() => {
    console.log("执行increment2函数");
    setCount(count + 1);
  }, [count]);

  return (
    <div>
      <h2>CallbackHookDemo01: {count}</h2>
      <HYButton title="btn1" increment={increment1}/>
      <HYButton title="btn2" increment={increment2}/>
      <button onClick={e => setShow(!show)}>show切换</button>
    </div>
  )
}

总结:

  • useCallback使用场景:在将一个父组件中的函数传递给子组件进行回调使用时,且子组件进行了memo或者继承了pureComponent,能够达到避免子组件重新渲染的目的。
  • 改变哪个变量,只应该让该变量对应的视图重新渲染,其他的应该充分利用缓存。

参考链接:react hooks:1.30分

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

. . . . .

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值