Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React优化:竭尽全力的减少render渲染 #3

Open
chenlong-io opened this issue May 25, 2018 · 0 comments
Open

React优化:竭尽全力的减少render渲染 #3

chenlong-io opened this issue May 25, 2018 · 0 comments

Comments

@chenlong-io
Copy link
Owner

chenlong-io commented May 25, 2018

前言

玩过React的同学都知道,render()方法除了第一次组件被实例化,其他情况绝大多数是state改变触发的。

而render方法的执行,所带来的负担就是重新对比Virtual DOM(虚拟DOM树),也就是重新执行Diff算法,然后把要修改的的DOM重新update。

而我们总是在开发过程中会产生非常多不必要的重新渲染

如何减少render的触发,是提升项目性能的关键之一。

入手点

减少render的入口在哪?当然是要知道哪些情况会触发render啦~

根据个人了解,触发render有以下两种情况:

  1. 组件实例化
  2. state变化、props变化

那么我们从这两点入手

优化

Immutable 和 componentShouldUpdate

《React和Immutable》中,提到了使用Immutable配合React的componentShouldUpdate生命周期函数来减少不必要的render,效果非常明显,这里就不说了,建议大家一定去看一下

除了使用 Immutable ,还有其他方法来避免render执行吗?

先看看正常开发中,使用setState的情况:

constructor(props) {
    super(props);
    this.state = {};
  }

  render() {
    console.log('render');
    return (
      <div>
        <input onChange={this.change} />
        <button onClick={this.submit}>提交</button>
      </div>
    );
  }

 change = e => {
    this.setState({
      value: e.target.value
    });
  };

  submit = () => {
    console.log(this.state.value);
  };

执行上面代码,然后在input里输入123,看看控制台上发生了什么:

4

对没错,执行了3次render,我们想象一下,用户在登录界面输入账号和密码时,render 会执行多少次啊啊啊 简直要命。

那有什么方法可以解决呢?

使用防抖来减少render

防抖函数应用在高频率操作时,能避免无意义的代码执行,从而提高性能。

constructor(props) {
    super(props);
    this.state = {
      inputVal: ''
    };
  }

  render() {
    console.log('render');
    return (
      <div style={{ margin: 50 }}>
        <input onChange={this.change} />
        <button onClick={this.submit}>提交</button>
      </div>
    );
  }

  timer = null;
  change = e => {
    //获取inputVal
    const inputVal = e.target.value;

    //防抖处理
    clearTimeout(this.timer);
    this.timer = setTimeout(() => {
      //set值
      this.setState({
        inputVal
      });
    }, 200);
  };

  submit = () => {
    console.log(this.state.inputVal);
  };

我们依然将inputVal挂在state上面,由于onChange事件可以频繁的触发setState,所以我们从这里下手,在onChange事件里使用防抖来避免频繁触发setState,从而避免多次render带来的性能消耗。

我们在文本框里输入值,然后看看控制台打印的结果:

7

Yes! 可以看到 我们输入 Hello,控制台只打印出了一次 render ,非常好!

在开发中可以将防抖函数放在工具函数中方便调用哟~

减少setState 使用私有属性

现在我们改变一种写法:不使用setState而是换成私有属性this.inputVal来代替:

constructor(props) {
    super(props);
    this.inputVal;
  }

  render() {
    console.log('render');
    return (
      <div style={{ margin: 50 }}>
        <input onChange={this.change} />
        <button onClick={this.submit}>提交</button>
      </div>
    );
  }

  change = e => {
    this.inputVal = e.target.value;
  };

  submit = () => {
    console.log(this.inputVal);
  };

我们仍然输入123,然后看看控制台:

5

哇塞~~ render一次都没执行,现在点击提交,打印结果是 123,这正是我们想要的。

缺点

聪明的同学能发现一个问题,其实这样的优化有一个缺点:不能使用双向绑定

在开发中,真正使用双向绑定的表单元素,一般会有其他效果必须依赖该表单元素的数据,比如省市区级联,市区的变化必须依赖省的数据。

所以如果没有必要使用双向绑定的,请尽量避免使用。

总结

减少render的执行次数,可以使用:

  • Immutable 配合 shouldComponentUpdate 具体请看这里
  • 使用防抖函数来减少不必要的setState,从而减少render次数
  • 使用私有属性来替代setState
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant