最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • React的性能优化(useMemo和useCallback)的使用

    正文概述 掘金(水痕001)   2021-05-23   624

    一、业务场景

    • 1、使用类定义一个父组件

      export default class Parent extends React.Component {
        state = {
          count: 0,
        }
        render() {
          return(
            <div>
              我是父组件
              <button onClick={() => this.setState({count: this.state.count++})}>点击按钮</button>
              <Child />
            </div>
          )
        }
      }
      
    • 2、定义一个子组件

      class Child extends React.Component {
        render() {
          console.log('我是子组件');
          return (
            <div>
              我是子组件
              <Grandson />
            </div>
          )
        }
      }
      
    • 3、定义一个孙子组件

      class Grandson extends React.Component {
        render() {
          console.log('孙子组件')
          return(<div>孙子组件</div>)
        }
      }
      
    • 4、上面几个组件是比较标准的react的类组件,函数组件也是类似的,当你在父组件中点击按钮,其实你仅仅是想改变父组件内的count的值,但是你会发现每次点击的时候子组件和孙组件也会重新渲染,因为react并不知道是不是要渲染子组件,需要我们自己去判断。

    一、类组件中使用shouldComponentUpdate生命周期钩子函数

    • 1、在子组件中使用shouldComponentUpdate来判断是否要更新,

      class Child extends React.Component {
        shouldComponentUpdate (nextProps, nextState) {
          console.log(nextProps, this.props);
          if (nextProps.count === this.props.count) {
            return false;
          } else {
            return true;
          }
        }
        ...
      }
      

      **注意点:**这里的count是要父组件给当前组件传递的参数(就是你要监听变化的的来更新当前组件),如果你写一个nextProps.name === this.props.name其实,父组件并没有给当前组件传递name那么下面都是返回false组件不更新

    • 2、当子组件没更新,那么孙组件同样的不更新数据

    二、使用PureComponet语法糖

    • 1、子组件中继承

      class Child extends React.PureComponent {
        render() {
          console.log('我是子组件');
          return (
            <div>
              我是子组件
              <Grandson />
            </div>
          )
        }
      }
      
    • 2、在父组件中使用

      // 下面这种情况不会重新渲染子组件
      <Child/>
      // 下面这种情况下会重新渲染子组件
      <Child count={this.state.count}/>
      

    三、memo的使用

    • 1、组件定义(这里也可以使用类组件)

      function Child () {
        console.log('我是子组件');
        return (
          <div>
            子组件
          </div>
        )
      }
      
      function Parent () {
        const [count, setCount] = useState(0);
        return (
          <div>
            我是父组件-{count}
            <button onClick={()=>setCount(count + 1)}>点击按钮</button>
            <Child />
          </div>
        )
      }
      
    • 2、这里我们父组件内部改变count并没有传递给子组件,但是子组件一样的重新渲染了,这并不是我们希望看到的,因为需要对子组件包装下

      function Child () {
        console.log('我是子组件');
        return (
          <div>
            子组件
          </div>
        )
      }
      
      const ChildMemo = React.memo(Child);
      function Parent () {
        const [count, setCount] = useState(0);
        return (
          <div>
            我是父组件-{count}
            <button onClick={()=>setCount(count + 1)}>点击按钮</button>
            {/* 这种情况下不会渲染子组件 */}
            <ChildMemo />
            {/* 这种情况下会渲染子组件 */}
            <ChildMemo count={count}/>
          </div>
        )
      }
      

    四、useMemouseCallback的认识

    • 1、useMemouseCallback都是具有缓存作用的,只是他们缓存对象不一样,一个是属性,一个是缓存函数,特点都是,当缓存依赖的没变,去获取还是获取曾经的缓存

    • 2、useMemo是对函数组件中的属性包装,返回一个具有缓存效果的新的属性,当依赖的属性没变化的时候,这个返回新属性就会从缓存中获取之前的。

    • 3、useCallback是对函数组件中的方法缓存,返回一个被缓存的方法

    五、useMemo的使用(我们依赖借用子组件更新的来做)

    • 1、根据上面的方式我们在父组件更新数据,观察子组件变化

      const Child = (props) => {
        console.log('重新渲染子组件', props);
        return (
          <div>子组件</div>
        )
      }
      const ChildMemo = React.memo(Child);
      
      const Parent = () => {
        const [count, setCount] = useState(0);
        const [number, setNumber]=useState(0)
        const userInfo = {
          age: count,
          name: 'hello',
        }
      
        const btnHandler = () => {
          setNumber(number+1);
        }
        return (
          <div>
            {number}-{count}
            <button onClick={btnHandler}>按钮</button>
            <ChildMemo userInfo={userInfo}/>
          </div>
        )
      }
      

      上面发现我们仅仅是更新了number的值,传递给子组件的对象值并没有变化,但是每次子组件都重新更新了,虽然我们在子组件上用了React.memo包装还是不行,这是因为在父组件中每次重新渲染,对于对象来说会是重新一个新的对象了。因此子组件要重新更新,

    • 2、使用useMemo对属性的包装

      const userInfo = useMemo(() => {
        return {
          age: count,
          name: 'hello',
        };
      }, [count]);
      

      使用useMemo包装后的对象,重新返回一个具有缓存效果的新对象,第二个参数表示依赖性,或者叫观察对象,当被观察的没变化,返回的就是缓存对象,如果被观察的变化了,那么就会返回新的,现在不管你怎么更新number的值,子组件都不会重新更新了

    • 3、注意点:useMemo要配合React.memo来使用,不然传递到子组件也是不生效的

    六、useCallback的使用

    前面介绍了,useCallback是对一个方法的包装,返回一个具有缓存的方法,常见的使用场景是,父组件要传递一个方法给子组件

    • 1、在不使用useCallback的时候

      const Child = (props) => {
        console.log('渲染了子组件');
        const { onClick } = props;
        return (
          <button onClick={onClick}>点击按钮获取值</button>
        )
      }
      
      const ChildMemo = React.memo(Child);
      
      const Parent = () => {
        const [text, updateText] = useState('');
        const textRef = useRef(text);
        const handleSubmit = () => {
          console.log('当前的值', text);
        }
        return(
          <div>
            我是父组件
            <input type="text" value={text} onChange={(e) => updateText(e.target.value)}/>
            <ChildMemo onClick={handleSubmit}/>
          </div>
        )
      }
      

      结果是每次输入框输入值的时候,子组件就会重新渲染一次,其实子组件中仅仅是一个按钮,要获取最终输入的值,每次父组件输入值的时候,子组件就更新,很耗性能的

    • 2、使用useCallback来包装一个方法

      const Parent = () => {
        const [text, updateText] = useState('');
        const textRef = useRef();
      
        // useCallback又依赖了textRef的变化,因此可以获取到最新的数据
        const handleSubmit = useCallback(() => {
          console.log('当前输入框的值:', textRef.current);
        }, [textRef])
      
        // 当text的值变化的时候就会给textRef的current重新赋值
        useEffect(() => {
          textRef.current = text;
        }, [text]);
        
        return(
          <div>
            我是父组件
            <input type="text" value={text} onChange={(e) => updateText(e.target.value)}/>
            <ChildMemo onClick={handleSubmit}/>
          </div>
        )
      }
      

    起源地下载网 » React的性能优化(useMemo和useCallback)的使用

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元