MST

星途 面试题库

面试题:React组件生命周期在性能优化中的应用

在React应用性能优化场景下,如何利用shouldComponentUpdate和getSnapshotBeforeUpdate这两个生命周期方法来提升性能?请结合具体代码示例说明。
43.4万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试

shouldComponentUpdate

shouldComponentUpdate 方法允许我们在组件接收到新的 props 或 state 时,决定是否需要重新渲染组件。通过实现这个方法,我们可以避免不必要的渲染,从而提升性能。

以下是一个简单的示例,假设有一个展示用户信息的组件 UserInfo

import React, { Component } from'react';

class UserInfo extends Component {
  constructor(props) {
    super(props);
    this.state = {
      // 假设这里有一些组件内部状态
      internalData: 'initial value'
    };
  }

  shouldComponentUpdate(nextProps, nextState) {
    // 比较当前 props 和 nextProps,只在必要时返回 true
    if (this.props.user.name!== nextProps.user.name) {
      return true;
    }
    // 比较当前 state 和 nextState,只在必要时返回 true
    if (this.state.internalData!== nextState.internalData) {
      return true;
    }
    return false;
  }

  render() {
    return (
      <div>
        <p>Name: {this.props.user.name}</p>
        <p>Age: {this.props.user.age}</p>
      </div>
    );
  }
}

export default UserInfo;

在上述代码中,shouldComponentUpdate 方法检查新的 props.user.name 和当前的 props.user.name 是否不同,以及新的 state.internalData 和当前的 state.internalData 是否不同。只有在这些值发生变化时,才返回 true 允许组件重新渲染,否则返回 false 阻止不必要的渲染。

getSnapshotBeforeUpdate

getSnapshotBeforeUpdate 方法在最近一次渲染输出(提交到 DOM 节点)之前调用。它可以用于在 DOM 更新之前捕获一些信息(例如滚动位置),然后在 componentDidUpdate 中使用这些信息。

以下是一个滚动列表的示例,在列表更新时保持滚动位置:

import React, { Component } from'react';

class ScrollableList extends Component {
  constructor(props) {
    super(props);
    this.state = {
      items: [1, 2, 3, 4, 5]
    };
    this.listRef = React.createRef();
  }

  handleAddItem = () => {
    const newItem = this.state.items.length + 1;
    this.setState(prevState => ({
      items: [...prevState.items, newItem]
    }));
  };

  getSnapshotBeforeUpdate(prevProps, prevState) {
    if (prevState.items.length!== this.state.items.length) {
      const list = this.listRef.current;
      return list.scrollTop;
    }
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    if (snapshot!== null) {
      const list = this.listRef.current;
      list.scrollTop = snapshot;
    }
  }

  render() {
    return (
      <div>
        <ul ref={this.listRef}>
          {this.state.items.map(item => (
            <li key={item}>{item}</li>
          ))}
        </ul>
        <button onClick={this.handleAddItem}>Add Item</button>
      </div>
    );
  }
}

export default ScrollableList;

在这个例子中,getSnapshotBeforeUpdate 方法在列表长度发生变化时,捕获当前列表的滚动位置 scrollTop 并返回。然后在 componentDidUpdate 方法中,利用捕获到的滚动位置 snapshot 恢复列表的滚动位置,从而提升用户体验并避免不必要的滚动位置重置带来的性能开销。