React组件化开发(一)

React性能优化之SCU

原因

  • 只要是修改了App中的数据,所有的组件都需要重新render,进行diff算法,性能必然是很低的:
    • 事实上,很多的组件没有必须要重新render
    • 它们调用render应该有一个前提,就是依赖的数据(stateprops)发生改变时,再调用自己的render方法;
  • 如何来控制render方法是否被调用呢?
    • 通过shouldComponentUpdate方法即可;

什么是SCU优化?

  1. shouldComponentUpdate — SCU — React提供给我们的生命周期方法

    • SCU优化就是 一种巧妙的技术,用来减少DOM操作次数,具体为当React元素没有更新时,不会去调用render()方法
    • 可以通过shouldComponentUpdate来判断this.state中的值是否改变
  2. SCU 这个方法接受参数,并且需要有返回值:

    • 该方法有两个参数:
      • 参数一:nextProps 修改之后,最新的props属性
      • 参数二:nextState 修改之后,最新的state属性
    • 该方法返回值是一个boolean类型:
      • 返回值为true,那么就需要调用render方法;
      • 返回值为false,那么就不需要调用render方法;
      • 默认返回的是true,也就是只要state发生改变,就会调用render方法;
shouldComponentUpdate(nextProps, nextState) {
  // 从当前状态state中获取message和counter
  const {message, counter} = this.state 

  // 如果message或counter与将要最新的状态nextState中不同,则返回true,表示需要更新组件。
  if(message !== nextState.message || counter !== nextState.counter) {
    return true
  }

  // 否则返回false,表示状态未发生变化,组件不需要更新。
  return false 
}

React已经帮我们提供好SCU优化的操作

类组件: 将class继承自 PureComponent :

  • shallowEqual方法
    React组件化开发(一)

    • 调用 !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState),这个shallowEqual就是进行浅层比较:
    //这个函数的目的是对比两个对象的浅层差异并返回布尔值,表示是否相等。如果两个对象具有相同的属性和值,则它们被认为是相等的。
      function shallowEqual(objA, objB) {
      // 如果两个对象完全相同,则返回true
      if (Object.is(objA, objB)) {
        return true;
      }

      // 如果objA和objB中有一个不是对象类型或为null,则返回false
      if (
        typeof objA !== 'object' ||
        objA === null ||
        typeof objB !== 'object' ||
        objB === null
      ) {
        return false;
      }

      // 获取objA和objB的所有属性名,并存储在数组keysA和keysB中
      const keysA = Object.keys(objA);
      const keysB = Object.keys(objB);

      // 如果objA和objB的属性数量不相等,则返回false
      if (keysA.length !== keysB.length) {
        return false;
      }

      // 检查objA的每个属性是否都存在于objB中,
      // 并且它们的值是否完全相等
      for (let i = 0; i < keysA.length; i++) {
        if (
          !hasOwnProperty.call(objB, keysA[i]) || // objB中不存在该属性
          !Object.is(objA[keysA[i]], objB[keysA[i]]) // 属性值不相等
        ) {
          return false;
        }
      }

      // 如果objA和objB的所有属性都相等,则返回true
      return true;
    }


函数组件: 使用一个高阶组件memo

  • React.memo() 是 React 中的一个高阶组件,用于优化函数式组件的性能。它能够在组件 props 没有变化时,避免不必要的重新渲染。

  • React.memo() 函数接收一个 React 组件作为参数,并返回一个包装后的组件。这个包装后的组件与原始组件具有相同的 API,但是会进行一些性能上的优化。

  • 使用 React.memo() 包装的组件将对其 props 进行浅层比较(shallow comparison),只有当 props 发生变化时才进行重新渲染。因此,如果你知道组件的 props 变化频率不高,可以使用 React.memo() 来减少组件不必要的重复渲染。

    import {mome} from 'react'

    const HomeFunc = mome(function(props) {
      return (
        <h4>函数式组件: {props.message}</h4>
      )
    })

    export default HomeFunc

React 强调不可变的力量

不可变的力量: 不要直接去修改this.state中的值(主要指对象),若是想修改的话,应该是将这整个值全部修改掉。
注意: 值类型,在修改的时候,本身就全部替换掉了,所以不需要其他操作,直接改就可以

  • React 强调不可变的力量,是因为在 React 中使用不可变数据结构可以提高组件性能,并且使得代码更加健壮和易于维护。

  • 使用不可变数据结构可以避免在直接修改数据时发生意外的副作用,例如无意中修改了 stateprops 对象,导致组件状态混乱或者重新渲染。同时,不可变数据结构还可以优化性能,因为它们能够让 React 更好地判断哪些部分的数据发生了变化,从而避免不必要的重新渲染。

  • React 中推荐的不可变数据结构主要包括以下几种:

    • 数组:使用 concat()slice()map()filter() 等方法创建新数组。
    • 对象:使用 ES2015 的扩展运算符(spread operator)或 Object.assign() 创建新对象。
    • Map 和 Set:使用其内置的 set()delete()clear() 等方法。
  • 总的来说,实现不可变的力量需要遵循以下原则:

    1. 尽可能使用 const 声明变量,确保不会意外地修改值。

    2. 不直接修改 state 或 props 中的值,而是创建新的对象或数组,从而避免副作用。

    3. 在传递数组或对象给子组件时,也要确保传递给子组件的是新的副本,而不是原始对象的引用。

    4. 合理地使用 JavaScript 提供的不可变数据结构,如数组、对象、Map 和 Set 等,可以更方便地支持不可变性,并提高代码的健壮性和可维护性。

下面是一些在 React 中实现不可变性的例子:

  1. 使用 concat() 方法创建新数组
function MyComponent(props) {
  const [items, setItems] = useState([]);

  function addItem(newItem) {
    // 使用concat()方法来创建新数组,并将新元素添加到末尾
    setItems(items.concat(newItem));
  }

  return (
    <div>
      {items.map((item, index) => (
        <div key={index}>{item}</div>
      ))}
    </div>
  );
}
  1. 使用扩展运算符创建新对象
function MyComponent(props) {
  const [user, setUser] = useState({ name: 'Alice', age: 30 });

  function updateUser(newName) {
    // 使用扩展运算符创建一个新的对象,并更新name属性
    setUser({ ...user, name: newName });
  }

  return (
    <div>
      <div>Name: {user.name}</div>
      <div>Age: {user.age}</div>
      <button onClick={() => updateUser('Bob')}>Update Name</button>
    </div>
  );
}
  1. 使用 Map 数据结构创建新 Map
function MyComponent(props) {
  const [myMap, setMyMap] = useState(new Map());

  function addMapEntry(key, value) {
    // 创建一个新Map对象,并使用set()方法添加新的键值对
    const newMap = new Map(myMap);
    newMap.set(key, value);
    setMyMap(newMap);
  }

  return (
    <div>
      <ul>
        {[...myMap.entries()].map(([key, value]) => (
          <li key={key}>
            {key}: {value}
          </li>
        ))}
      </ul>
      <button onClick={() => addMapEntry('apple', 5)}>Add apple</button>
    </div>
  );
}

通过使用以上方式,我们可以避免直接修改数据并创建新的不可变数据结构。这些方法不仅能提高 React 组件的性能,同时也帮助我们写出更健壮和可维护的代码。

原文链接:https://juejin.cn/post/7225141192605548599 作者:星_墨

(0)
上一篇 2023年4月24日 上午10:00
下一篇 2023年4月24日 上午10:10

相关推荐

发表回复

登录后才能评论