React - componentDidMount中的setState

时间:2016-08-09 07:58:23

标签: reactjs

我正在为图像构建一个延迟加载组件。但我设置状态有问题。我收到只能更新已安装或正在安装的组件错误,但我在setState内使用componentDidMount,这样可以避免此类错误。

这是我的代码:

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

        this.element = null;

        this.state = {
            loaded: false,
            height: 0
        };
    }

    componentDidMount() {
        this.element = findDOMNode(this);

        this.loadImage();
    }

    getDimensions() {
        const w = this.element.offsetWidth;

        let initw = 0;
        let inith = 0;

        let result;

        const img = new Image();
        img.src = this.props.url;

        img.onload = (e) => {
            initw = e.path[0].width;
            inith = e.path[0].height;

            result = (w / initw) * inith;

            setTimeout(() => {
                this.setState({
                    loaded: true,
                    height: `${result}px`
                });
            });
        }
    }

    loadImage() {
        _scrolling.add([this.element], () => {
            if (this.element.classList.contains(_scrolling.classes.coming)) { // the image is visible
                this.getDimensions();
            }
        });
    }

    render() {
        const classes = this.state.loaded ? `${this.props.parentClass}__image--loaded` : null;
        const styles = this.state.loaded ? {
            maxHeight: this.state.height, minHeight: this.state.height, overflow: 'hidden'
        } : null;

        return (
            <div className={`${this.props.parentClass}__image ${classes}`} style={styles}>
                {this.state.loaded ?
                    <img
                        className={`${this.props.parentClass}__img`}
                        src={this.props.url}
                        title={this.props.title}
                        alt={this.props.title}
                    />
                    : null
                }
            </div>
        )
    }

我相信问题在于img.onload,但我不知道如何实现这一目标。我该怎么办?

2 个答案:

答案 0 :(得分:4)

如果您尝试在未安装的组件上设置状态,则会出现类似的错误。有两种解决方案:

  1. 确保组件已安装:在检查组件是否已安装后使用DECLARE v_counter int := 0 ; select count(*) into v_counter from ( cursor get_sth is select * from table1 where condit..) ; BEGIN DBMS_OUTPUT.PUT_LINE (v_counter); END ; /

  2. 中止请求:当组件卸载时,我们可以抛弃请求,以便永远不会调用回调。为此,我们将利用另一个React生命周期钩子setstate();

答案 1 :(得分:2)

似乎在未安装的img.onload组件实例上调用Images处理程序。

图像加载是异步的,需要一些时间。当它最终完成并调用img.onload处理程序时,无法保证您的组件仍然被挂载。

您必须使用componentWillUnmount并确保:

  • 在卸载组件之前取消图像加载,或
  • 跟踪组件的已安装状态,并在调用处理程序后检查它是否已挂载

有关检查组件是否已装入的更多信息:https://facebook.github.io/react/blog/2015/12/16/ismounted-antipattern.html

解决方案:取消图像加载

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

        this.element = null;

        this.state = {
            loaded: false,
            height: 0
        };

        this.images = []; // We’ll store references to the Image objects here.
    }

    componentDidMount() {
        this.element = findDOMNode(this);

        this.loadImage();
    }

    componentWillUnmount() {
        this.images.forEach(img => img.src = ''); // Cancel the loading of images.
    }

    getDimensions() {
        const w = this.element.offsetWidth;

        let initw = 0;
        let inith = 0;

        let result;

        const img = new Image();
        img.src = this.props.url;

        img.onload = (e) => {
            initw = e.path[0].width;
            inith = e.path[0].height;

            result = (w / initw) * inith;

            setTimeout(() => {
                this.setState({
                    loaded: true,
                    height: `${result}px`
                });
            });
        }

        this.images.push(img); // Store the reference.
    }

    loadImage() {
        _scrolling.add([this.element], () => {
            if (this.element.classList.contains(_scrolling.classes.coming)) { // the image is visible
                this.getDimensions();
            }
        });
    }

    render() {
        const classes = this.state.loaded ? `${this.props.parentClass}__image--loaded` : null;
        const styles = this.state.loaded ? {
            maxHeight: this.state.height, minHeight: this.state.height, overflow: 'hidden'
        } : null;

        return (
            <div className={`${this.props.parentClass}__image ${classes}`} style={styles}>
                {this.state.loaded ?
                    <img
                        className={`${this.props.parentClass}__img`}
                        src={this.props.url}
                        title={this.props.title}
                        alt={this.props.title}
                    />
                    : null
                }
            </div>
        )
    }
}

我复制了图像取消:https://stackoverflow.com/a/5278475/594458