MST
星途 面试题库

面试题:React 中 componentWillUnmount 与性能优化

假设一个 React 组件频繁地挂载和卸载,其中在 componentWillUnmount 中有一些异步清理任务。这可能会对性能产生什么影响?你会如何优化这种情况,以确保组件卸载时既完成必要清理,又不影响性能?
45.5万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试

对性能的影响

  1. 内存泄漏:如果在 componentWillUnmount 中的异步清理任务没有正确处理,当组件卸载后,这些异步任务可能仍然在执行,并且持有对组件或其内部状态的引用,导致组件及其相关资源无法被垃圾回收机制回收,从而造成内存泄漏。
  2. 阻塞后续操作:在频繁挂载和卸载组件的场景下,如果异步清理任务耗时较长,可能会阻塞后续组件的挂载操作,影响用户体验。

优化方法

  1. 使用 AbortController(适用于支持该 API 的环境)
    • 可以在组件挂载时创建一个 AbortController 实例,并在异步任务中使用它。
    • componentWillUnmount 中调用 abort 方法来取消异步任务。
    import React, { Component } from'react';
    
    class MyComponent extends Component {
      constructor(props) {
        super(props);
        this.abortController = new AbortController();
      }
    
      componentDidMount() {
        const { signal } = this.abortController;
        // 发起异步任务
        fetch('your-api-url', { signal })
         .then(response => response.json())
         .then(data => console.log(data))
         .catch(error => {
            if (error.name === 'AbortError') {
              // 任务被取消时的处理
              console.log('任务已取消');
            } else {
              console.error('请求错误:', error);
            }
          });
      }
    
      componentWillUnmount() {
        this.abortController.abort();
      }
    
      render() {
        return <div>My Component</div>;
      }
    }
    
    export default MyComponent;
    
  2. 手动管理异步任务状态
    • 定义一个标志变量来表示组件是否已经卸载。
    • 在异步任务的回调中检查这个标志变量,以决定是否继续执行后续操作。
    import React, { Component } from'react';
    
    class MyComponent extends Component {
      constructor(props) {
        super(props);
        this.isUnmounted = false;
      }
    
      componentDidMount() {
        setTimeout(() => {
          if (!this.isUnmounted) {
            // 模拟异步操作
            console.log('异步操作完成');
          }
        }, 1000);
      }
    
      componentWillUnmount() {
        this.isUnmounted = true;
      }
    
      render() {
        return <div>My Component</div>;
      }
    }
    
    export default MyComponent;
    
  3. 使用 useEffect 的清理函数(对于函数式组件)
    • useEffect 中返回一个清理函数,该清理函数会在组件卸载时执行。
    • 如果清理函数中有异步操作,同样可以采用上述两种方式来处理异步任务。
    import React, { useEffect } from'react';
    
    const MyComponent = () => {
      useEffect(() => {
        const controller = new AbortController();
        const { signal } = controller;
    
        // 发起异步任务
        fetch('your-api-url', { signal })
         .then(response => response.json())
         .then(data => console.log(data))
         .catch(error => {
            if (error.name === 'AbortError') {
              console.log('任务已取消');
            } else {
              console.error('请求错误:', error);
            }
          });
    
        return () => {
          controller.abort();
        };
      }, []);
    
      return <div>My Component</div>;
    };
    
    export default MyComponent;