面试题答案
一键面试可能引入内存泄漏问题的生命周期方法
componentDidMount
:在此方法中常进行一些副作用操作,如添加事件监听器、订阅消息等。若在组件销毁时没有清理这些操作,就会导致内存泄漏。例如:
import React, { Component } from'react';
class MemoryLeakComponent extends Component {
componentDidMount() {
window.addEventListener('scroll', this.handleScroll);
}
handleScroll = () => {
console.log('Window scrolled');
}
render() {
return <div>Component with potential memory leak</div>;
}
}
export default MemoryLeakComponent;
在上述代码中,componentDidMount
里添加了 window
的 scroll
事件监听器,但未清理。
componentWillUpdate
:虽然该方法已被废弃(在 React 17+ 中使用getSnapshotBeforeUpdate
替代),在旧版本中若在此方法中进行一些未清理的异步操作,如启动定时器等,且在组件销毁时未清除定时器,也会引发内存泄漏。例如:
import React, { Component } from'react';
class OldLeakComponent extends Component {
componentWillUpdate() {
this.timer = setInterval(() => {
console.log('Timer running');
}, 1000);
}
render() {
return <div>Old component with potential leak</div>;
}
}
export default OldLeakComponent;
避免内存泄漏及性能优化的方法
- 针对
componentDidMount
中的副作用操作:在componentWillUnmount
生命周期方法中清理相应操作。例如,对于前面添加的scroll
事件监听器,修改如下:
import React, { Component } from'react';
class FixedMemoryLeakComponent extends Component {
handleScroll = () => {
console.log('Window scrolled');
}
componentDidMount() {
window.addEventListener('scroll', this.handleScroll);
}
componentWillUnmount() {
window.removeEventListener('scroll', this.handleScroll);
}
render() {
return <div>Component without memory leak</div>;
}
}
export default FixedMemoryLeakComponent;
- 针对异步操作(如定时器):在
componentWillUnmount
中清除定时器。对于前面的定时器示例,修改如下:
import React, { Component } from'react';
class FixedOldLeakComponent extends Component {
componentWillUpdate() {
this.timer = setInterval(() => {
console.log('Timer running');
}, 1000);
}
componentWillUnmount() {
if (this.timer) {
clearInterval(this.timer);
}
}
render() {
return <div>Old component without leak</div>;
}
}
export default FixedOldLeakComponent;
- 使用 React Hooks 时:对于副作用操作,可以使用
useEffect
钩子。useEffect
的第二个参数可以传入依赖数组,若依赖数组为空,其效果类似componentDidMount
。并且可以在返回函数中进行清理操作,类似componentWillUnmount
。例如:
import React, { useEffect } from'react';
const HookComponent = () => {
const handleScroll = () => {
console.log('Window scrolled');
}
useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);
return <div>Hook component without memory leak</div>;
};
export default HookComponent;