0

问题:

我将 react-slick 与 react-preload-image (两者的最新版本)结合使用来创建具有多个滑块导轨的页面。这个想法是按类别显示我的投资组合,因此我使用 react-slick 列出每个类别以显示图像,并使用 react-preload-image 显示预加载图像,然后显示投资组合图像。

好消息是,只要我不调整浏览器窗口的大小,它就会看起来很棒,并且完全符合我的要求。坏消息是,当我缩小浏览器窗口(减小宽度)时,应用程序完全崩溃 - 空白屏幕,控制台中有很多丑陋的消息,如下所示:

    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)

问题似乎发生在 react-preload-image 上。每张图片我都会得到其中一个条目(所以 40 张图片,其中 40 个警告)。

我已经以几种不同的方式对其进行了重构以尝试解决此问题,但均无济于事。这是我的组件及其代码:

PortCatRails.js - 创建所有导轨

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

PortfolioRail.js - 使用 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 - 轨道中每个投资组合项一个组件


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 - 显示带有预加载器的给定图像

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

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

}

最后一条线索: 正如我所说,我只有在缩小浏览器窗口时才会收到错误消息,而且只有在它遇到设置中的一个断点时才会出现错误,所以这不是巧合。我只是不知道在这一点上如何处理它。

如果有人见过这样的东西,我很想知道它的修复方法。这是迄今为止我唯一喜欢的图像预加载器(我已经尝试了几个)。

谢谢!

4

1 回答 1

0

所以我不知道这个问题是否是我的实现所独有的,但我找到了解决方法。显然 react-preload-image 中存在一些错误,但它是一个超级简单的单行修复。

在 index.js 文件的第 66 行,只需更改以下内容:

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

对此:

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

而且插件效果很好。我已经让作者知道了,希望他能在下一个版本中实现这一点。

于 2019-09-18T12:46:13.890 回答