简体   繁体   中英

React, setState warning for mounted/unmounted component

I have a react component I am using to load my images progressively for my app which has been working great for me. When I use it on a page to load images, though, I am seeing an error:

warning.js:35 Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op.

Multiple times - looks like once for each image called. It does not seem to be effecting anything seriously as the image components still work. I am wondering how to get rid of this error though, I cannot figure out how.

So here is my component:

import React, { PropTypes } from 'react';

require('./progressive-image.scss');

export default class ProgressiveImage extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      loaded: false,
      image: props.smallImg
    };

    this.loadImage = this.loadImage.bind(this);
    this.onLoad = this.onLoad.bind(this);
    this.onError = this.onError.bind(this);
    this.image = undefined;
  }

  componentDidMount() {
    const { largeImg } = this.props;
    this.loadImage(largeImg);
  }

  onError(err) {
    console.warn('Error loading progressive image :', err);
  }

  onLoad() {
    this.setState({
      loaded: true,
      image: this.image.src
    });
  }

  componentDidUpdate(nextProps) {
    const { largeImg, smallImg } = nextProps;

    if (largeImg !== this.props.largeImg) {
      this.setState({ loaded: false, image: smallImg }, () => {
        this.loadImage(largeImg);
      });
    }
  }


  loadImage(src) {
    if (this.image) {
      this.image.onload = null;
      this.image.onerror = null;
    }

    const image = new Image();
    this.image = image;
    image.onload = this.onLoad;
    image.onerror = this.onError;
    image.src = src;
  }

  render() {
    const imgStyle = { 'paddingBottom': this.props.heightRatio };
    const { imgAlt, imgTitle } = this.props;

    return (
      <div className={`progressive-placeholder ${this.state.loaded ? 'loaded' : ''}`}>
        {this.state.loaded &&
          <img
            alt={imgAlt}
            className={`loaded`}
            src={this.state.image}
            title={imgTitle}
             />
        }
        <img className={`img-small ${!this.state.loaded ? 'loaded' : ''}`} src={this.state.image} alt="placeholder image for loading"/>
        <div style={imgStyle} ></div>
      </div>
    );
  }
}

ProgressiveImage.displayName = 'ProgressiveImage';

ProgressiveImage.propTypes = {
  bgColor: PropTypes.string,
  heightRatio: PropTypes.string.isRequired,
  largeImg: PropTypes.string.isRequired,
  smallImg: PropTypes.string.isRequired,
  imgAlt: PropTypes.string,
  imgTitle: PropTypes.string,
};

So the only time setState is called is when onLoad or componentDidUpdate is called. My thinking is that because its only called did mount and did update it should not be getting this error. Looking for any insight on how to clean up this error, as it has me puzzled. If any additional info is needed, I am happy to provide.

The problem is your callback in image.onload could be called at any random point :

    image.onload = this.onLoad;

Chances are this.onLoad is being called while your component is rendering.

The problem is that because this.onLoad is called when your external image resource loads then when you are doing this.setState , your component could be rendering and this would cause the error .

To handle this I would recommend setting the loaded / image values outside of the local Component state and instead dispatch it to a global state using something like redux .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM