简体   繁体   中英

Errors with React Image Preload and React-Slick

The problem:

I'm using react-slick in conjunction with react-preload-image (latest versions on both) to create a page with multiple slider rails. The idea is to show my portfolio by category, so I'm listing out each category using react-slick to display images and react-preload-image to show the preload image and then the portfolio image.

The good news is that as long as I don't resize the browser window, it looks great and does exactly what I want it to. The bad news, is that when I resize down my browser window (decrease width) the app completely crashes - blank screen, lots of ugly messages in my console, as follows:

    Uncaught TypeError: Cannot set property 'onload' of undefined
    at PreloadImage.componentWillUnmount (index.js:66)
    at callComponentWillUnmountWithTimer (react-dom.development.js:19866)
    at HTMLUnknownElement.callCallback (react-dom.development.js:347)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:397)
    at invokeGuardedCallback (react-dom.development.js:454)
    at safelyCallComponentWillUnmount (react-dom.development.js:19873)
    at commitUnmount (react-dom.development.js:20293)
    at commitNestedUnmounts (react-dom.development.js:20349)
    at unmountHostComponents (react-dom.development.js:20645)

The problem appears to be happening with react-preload-image. I get one of these entries per image (so 40 images, 40 of these warnings).

I've refactored this in several different ways to try to work around this, all to no avail. Here are my components and their code:

PortCatRails.js - creates all the rails

    return (
        <div>
            {
                portcats.map((cat) => {
                    return (
                        <PortfolioRail key={uuid()} title={cat.name} catId={cat.id} />
                    )
                })
            }
        </div>
    );

PortfolioRail.js - creates each rail using react-slick



class PortfolioRail extends React.Component {
    constructor(props) {
        super(props)
    }

    render() {

          const portItems = this.props.portfolio.filter((item) => {     
              return (item.portcats && item.portcats.indexOf(this.props.catId+'') !== -1)                    
          })

          const settings = {
            dots: false,
            className: "center",
            centerPadding: "80px",
            infinite: true,
            speed: 500,
            slidesToScroll: 1,
            centerMode: false,
            ladyLoad: true,
            slidesToShow: 5,
            responsive: [
                {
                    breakpoint: 576,
                    settings: {
                        slidesToShow: 1,
                        slidesToScroll: 1,
                        arrows: false,
                        swipeToSlide: true,
                        centerMode: true
                    }
                },
                {
                    breakpoint: 768,
                    settings: {
                        slidesToShow: 2,
                        slidesToScroll: 1,
                        arrows: false,
                        swipeToSlide: true,
                        centerMode: true
                    }
                },
                {
                    breakpoint: 992,
                    settings: {
                        slidesToShow: 3,
                        slidesToScroll: 1,
                        arrows: true,
                        centerMode: false
                    }
                },
                {
                    breakpoint: 1900,
                    settings: {
                        slidesToShow: 4,
                        slidesToScroll: 1,
                        arrows: true,
                        swipeToSlide: false,
                        centerMode: false
                    }
                }
            ]
          };    

        return (
            portItems.length > 0 &&
            <div>
                <h4>{this.props.title}</h4>
                <Slider {...settings}>
                    {portItems.map((item) => {
                        return (
                            <PortRailItem data={item} key={uuid()} />
                        )
                    })}
                </Slider>
            </div>
        )
    }
}

PortfolioRailItem.js - One Component Per Portfolio Item in a rail


const PortRailItem = (props) => {
    const {projectTitle, shortDesc, propcats, previewImg} = props.data;
    const [infoClass, setInfoClass] = useState('');


    const handleMouseEnter = (e) => {
        setInfoClass('railItem__info--expanded');
    }

    const handleMouseLeave = (e) => {
        setInfoClass('');
    }

    return (
        <div>
            <div className="railItem__outer" onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
                <div className="railItem__inner">
                    <ImageWithPreloader src={previewImg} className="railitem__img-preloader" />
                    <div className={`railItem__info ${infoClass}`}>
                        <h5>{projectTitle}</h5>
                        <div className={`railItem__info--short-desc ${infoClass}`}>
                        {shortDesc}
                        </div>
                    </div>
                </div>
            </div>
        </div>
    )
}

ImageWithPreloader.js - displays the given image with a preloader

const ImageWithPreloader = (props) => {
    const {src, className = 'img-peloader', duration = '1000ms' } = props;

    return (
        <PreloadImage 
            src={src}
            className={className}
            duration={duration}
            lazy
        />
    )

}

ONE FINAL CLUE: As I said, I only get the error when downsizing the browser window, and ONLY when it hits one of the breakpoints in the settings, so it's no coincidence. I'm just not sure how to handle it at this point.

If anybody has seen something like this, I'd love to know the fix for it. This is the only image preloader that I like so far (and I've tried several).

Thanks!

So I don't know if this problem is unique to my implementation, but I found a fix for it. Apparently there's a bit of a bug in the react-preload-image, but it's a super-easy one-line fix.

On line 66 of the index.js file, simply change this:

  PreloadImage.prototype.componentWillUnmount = function componentWillUnmount() {
    if (this.observer) this.observer.disconnect();
    this.preloader.onload = null;
  };

to this:

  PreloadImage.prototype.componentWillUnmount = function componentWillUnmount() {
    if (this.observer) this.observer.disconnect();

    // just add an if(this.preloader) to the next line and all is well
    if(this.preloader) this.preloader.onload = null;
  };

And the plugin works great. I've let the author know, hopefully he'll have this implemented in his next release.

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