blog icon indicating copy to clipboard operation
blog copied to clipboard

react 开发中,组件生命周期与异步操作之间的一个注意点

Open diamont1001 opened this issue 5 years ago • 0 comments

react 开发过程中,组件是必不可少的,而在一些实际的业务组件里,通常会包含一些异步操作,比如网络请求等。当组件已经被卸载了之后,异步回调处理中进行的一些比如 setState 等操作会存在内存泄漏的风险。

处理方式

对组件的 componentWillUnmount 事件做处理,当组件被卸载的时候,要不就去停止掉网络请求,要不就对 setState 等敏感操作进行判断。

比如,下面一个小组件的处理,可以参考一下(unmounted 变量是关键):

/**
 * 图片组件:自动获取图片大小
 */

import React, { Component } from 'react';
import { Image, Dimensions } from 'react-native';

const WinWidth = Dimensions.get('window').width;

export default class AutoSizedImage extends Component {
  constructor(props) {
    super(props);

    this.state = {
      finalSize: {
        width: 0,
        height: 0,
      },
    };

    this.unmounted = false; // 组件是否已被卸载
  }

  static defaultProps = {
    maxWidth: WinWidth,
    style: {},
    source: {
      uri: '',
    },
  };

  componentWillUnmount() {
    this.unmounted = true;
  }

  componentDidMount() {
    //avoid repaint if width/height is given
    if (this.props.style.width || this.props.style.height) {
      return;
    }

    // 不限定宽度的话,就取屏幕宽度
    const maxWidth = Math.min(this.props.maxWidth, WinWidth);

    Image.getSize(this.props.source.uri, (w, h) => { // 异步操作回调
      if (this.unmounted) { // 组件已卸载,不做操作
        console.log('[AutoSizedImage] component unmounted, abort.');
        return;
      }
      const finalSize = {
        width: w,
        height: h,
      };
      if (w > maxWidth) {
        finalSize.width = maxWidth;
        const ratio = finalSize.width / w;
        finalSize.height = h * ratio;
      }
      this.setState({
        finalSize,
      });
    });
  }

  render() {
    return (
      <Image
        {...this.props}
        resizeMode={'contain'}
        style={[
          this.props.style,
          this.state.finalSize.width && this.state.finalSize.height
            ? this.state.finalSize
            : null,
        ]}
      />
    );
  }
}

其他更多处理方式网上一大把,大家可以自行谷歌或者百度!!!

diamont1001 avatar Nov 08 '19 10:11 diamont1001