MST

星途 面试题库

面试题:React 组件生命周期中的内存泄漏场景及避免方法

React 从挂载到卸载经历多个生命周期阶段。请详细说明在哪些生命周期阶段可能会出现内存泄漏,并且针对每个可能出现泄漏的阶段,给出具体的避免内存泄漏的代码实现方式。
46.1万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试

可能出现内存泄漏的生命周期阶段及避免方法

  1. componentDidMount
    • 原因:在此阶段常进行一些副作用操作,如订阅事件、设置定时器等,如果在组件卸载时没有清理,就会导致内存泄漏。
    • 避免代码示例
import React, { Component } from'react';

class MyComponent extends Component {
    constructor(props) {
        super(props);
        this.handleScroll = this.handleScroll.bind(this);
    }
    componentDidMount() {
        window.addEventListener('scroll', this.handleScroll);
    }
    componentWillUnmount() {
        window.removeEventListener('scroll', this.handleScroll);
    }
    handleScroll() {
        // 处理滚动事件的逻辑
    }
    render() {
        return <div>My Component</div>;
    }
}

export default MyComponent;
  1. componentDidUpdate
    • 原因:如果在此阶段设置了定时器或订阅了事件,且没有在适当的时候清理,同样会引发内存泄漏。例如,每次更新都创建新的定时器而不清除旧的。
    • 避免代码示例
import React, { Component } from'react';

class UpdateComponent extends Component {
    constructor(props) {
        super(props);
        this.timer = null;
    }
    componentDidUpdate(prevProps, prevState) {
        if (prevProps.someProp!== this.props.someProp) {
            if (this.timer) {
                clearInterval(this.timer);
            }
            this.timer = setInterval(() => {
                // 定时器逻辑
            }, 1000);
        }
    }
    componentWillUnmount() {
        if (this.timer) {
            clearInterval(this.timer);
        }
    }
    render() {
        return <div>Update Component</div>;
    }
}

export default UpdateComponent;
  1. 使用第三方库的回调注册
    • 原因:在组件中使用第三方库,可能会注册一些回调函数,如果在组件卸载时没有反注册这些回调,会导致内存泄漏。例如使用 google - maps - api 注册的地图事件回调。
    • 避免代码示例:假设使用Google Maps API
import React, { Component } from'react';

class MapComponent extends Component {
    constructor(props) {
        super(props);
        this.map = null;
        this.mapListener = null;
    }
    componentDidMount() {
        const mapOptions = {
            center: { lat: 0, lng: 0 },
            zoom: 8
        };
        this.map = new window.google.maps.Map(document.getElementById('map'), mapOptions);
        this.mapListener = window.google.maps.event.addListener(this.map, 'click', () => {
            // 地图点击事件逻辑
        });
    }
    componentWillUnmount() {
        if (this.mapListener) {
            window.google.maps.event.removeListener(this.mapListener);
        }
    }
    render() {
        return <div id="map" style={{ height: '400px' }}></div>;
    }
}

export default MapComponent;

在React新的 hooks 写法中,useEffect 可以替代上述生命周期方法。使用 useEffect 时,返回一个清理函数来避免内存泄漏。例如:

import React, { useEffect } from'react';

const MyHookComponent = () => {
    useEffect(() => {
        const handleScroll = () => {
            // 处理滚动事件逻辑
        };
        window.addEventListener('scroll', handleScroll);
        return () => {
            window.removeEventListener('scroll', handleScroll);
        };
    }, []);
    return <div>Hook Component</div>;
};

export default MyHookComponent;