请选择 进入手机版 | 继续访问电脑版
MSIPO技术圈 首页 IT技术 查看内容

【前端知识】React 基础巩固(二十三)——React 性能优化 SCU相关

2023-07-13

React 基础巩固(二十三)——React 性能优化 SCU

React 更新机制

  • React 的渲染流程

    • JSX -> 虚拟 DOM -> 真实 DOM
  • React 的更新流程

    • props/state 改变 -> render函数重新执行 -> 产生新的DOM树 -> 新旧DOM树进行diff -> 计算出差异进行更新 -> 更新到真实的DOM
  • React 在 props 或 state 发生改变时,会调用 React 的 render 方法,会创建一颗不同的树

  • React 需要基于这两颗不同的树之间的差别来判断如何有效的更新 UI

    • 如果一颗树参考另外一颗树进行完全比较更新,那么即使时最先进的算法,该算法的复杂度为 O(n^2),其中 n 是树中元素的数量;
    • 如果在 React 中使用了该算法,那么展示 1000 个元素所需要执行的计算量将在 10 亿的量级范围;
    • 开销过于昂贵,更新性能非常低效;
  • 于是,React 对这个算法进行了优化,将其优化成了 O(n)

    • 同层节点之间相互比较,不会跨节点比较
    • 不同类型的节点,产生不同的树结构
    • 开发中,可以通过 key 来指定哪些节点在不同的渲染下保持稳定
  • keys 的优化

    • 遍历列表时,会提示一个警告,提示我们加入一个 key 属性
    • 当子元素拥有 key 时,React 使用 key 来匹配原有树上的子元素以及最新树上的子元素
      • 例如将 key 为 333 的元素插入到最前面的位置时,key 为 111,222 的元素,仅仅需要进行位移即可,不需要任何修改
  • key 的注意事项

    • key 应该是唯一的
    • key 不要使用随机数(随机数在下一次 render 时,会重新生成一个数字)
    • 使用 index 作为 key,对性能是没有优化的
  • render 函数被调用

    • 为了避免不必要的 render,提高性能,调用 render 应该有一个前提:依赖的数据(state、props)发生改变时,再调用 render 方法
  • 利用shouldComponentUpdate优化 render 调用


// 针对值发生变化的组件
shouldComponentUpdate(nextProps, newState){
  // 对比 state中的值是否有改变
  if (this.state.message !== newState.message || this.state.counter !== newState.counter){
    return true
  }
  return false
}

// 针对其中的子组件
shouldComponentUpdate(nextProps, newState){
  // 1.对比 state中的值是否有改变
  if (this.state.message !== newState.message || this.state.counter !== newState.counter){
    return true
  }
  // 2.检测接收的props是否有改变
  if (this.props.message !== newProps.message){
    return true
  }
  return false
}
  • 如果参数过多,SCU 的方式则过于繁琐,所以通常采用以下方式实现

针对类组件:采用PureComponent 实现优化

import React, { PureComponent } from "react";
export class App extends PureComponent {
  // ...
}

PureComponent中变更数组数据的实际应用:

import React, { PureComponent } from "react";

export class App extends PureComponent {
  constructor() {
    super();

    this.state = {
      books: [
        { name: "book1", price: 199, count: 1 },
        { name: "book2", price: 299, count: 1 },
        { name: "book3", price: 399, count: 2 },
        { name: "book4", price: 499, count: 3 },
        { name: "book5", price: 599, count: 1 },
      ],
    };
  }
  addNewBook() {
    const newBook = {
      name: "book6",
      price: 55,
      count: 1,
    };
    // 错误写法:
    // 直接修改原有的state,重新设置一遍
    // this.state.books.push(newBook);
    // this.setState({
    //   books: this.state.books,
    // });

    // 正确写法:
    // 拷贝一份,在新的数组中更新,设置新的books,而不是直接修改state
    const books = [...this.state.books];
    books.push(newBook);
    this.setState({ books });
  }

  addBookCount(index) {
    console.log(index);
    const books = [...this.state.books];
    books[index].count++;
    this.setState({ books });
  }

  render() {
    const { books } = this.state;
    return (
      <div>
        <h2>books list</h2>
        <ul>
          {books.map((item, index) => {
            return (
              <li key={index}>
                <span>
                  name: {item.name} - price: {item.price} - count: {item.count}
                </span>
                <button onClick={(e) => this.addBookCount(index)}>+1</button>
              </li>
            );
          })}
        </ul>
        <button onClick={(e) => this.addNewBook()}>添加新书籍</button>
      </div>
    );
  }
}

export default App;

针对函数式组件:采用 memo 实现优化

import { memo } from "react";
const Profile = memo(function (props) {
  console.log("profile render");
  return <h2>Profile: {props.message}</h2>;
});

export default Profile;

相关阅读

热门文章

    手机版|MSIPO技术圈 皖ICP备19022944号-2

    Copyright © 2024, msipo.com

    返回顶部