Pertanyaan Bereaksi - setState di dalam componentDidMount


Saya sedang membangun komponen malas untuk gambar. Tapi saya punya masalah dengan pengaturan negara. Saya mengerti Hanya dapat memperbarui komponen yang dipasang atau dipasang kesalahan, tapi saya gunakan setState dalam componentDidMount, yang seharusnya memungkinkan saya untuk menghindari kesalahan seperti itu.

Ini kode saya:

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>
        )
    }

Saya percaya masalahnya ada di dalam img.onload, tetapi saya tidak tahu bagaimana mencapai hal ini. Apa yang harus saya lakukan?


5
2017-08-09 07:58


asal


Jawaban:


Jika Anda mencoba menetapkan status pada komponen yang tidak di-mount, Anda akan mendapatkan kesalahan seperti itu.Ada dua solusi:

  1. Assure Component isMounted: gunakan setstate(); setelah memeriksa apakah komponen sudah terpasang atau belum.

  2. Batalkan Permintaan: Saat komponen tidak di-unmount, kami hanya dapat membuang permintaan sehingga callback tidak pernah dipanggil. Untuk melakukan ini, kami akan mengambil keuntungan dari hook siklus hidup React lainnya, componentWillUnmount.


4
2017-08-09 08:19



Sepertinya itu img.onload pawang mulai dipanggil di sebuah unmount Images contoh komponen.

Pemuatan gambar tidak sinkron dan membutuhkan waktu. Ketika akhirnya selesai dan img.onload handler dipanggil, tidak ada jaminan komponen Anda masih terpasang.

Anda harus memanfaatkan componentWillUnmount dan pastikan Anda juga:

  • Batalkan pemuatan gambar sebelum komponen dilepas, atau
  • Terus lacak status pemasangan komponen dan periksa apakah sudah terpasang setelah pawang Anda dipanggil

Lebih lanjut tentang memeriksa apakah suatu komponen dipasang atau tidak: https://facebook.github.io/react/blog/2015/12/16/ismounted-antipattern.html

Solusi: Batalkan Pemuatan Gambar

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>
        )
    }
}

Saya menyalin gambar membatalkan dari: https://stackoverflow.com/a/5278475/594458


2
2017-08-09 08:29