React Image Preload 和 React-Slick 的错误

Posted

技术标签:

【中文标题】React Image Preload 和 React-Slick 的错误【英文标题】:Errors with React Image Preload and React-Slick 【发布时间】:2019-09-18 00:14:42 【问题描述】:

问题:

我将 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
        />
    )


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

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

谢谢!

【问题讨论】:

【参考方案1】:

所以我不知道这个问题是否是我的实现所独有的,但我找到了解决方法。显然 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;
  ;

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

【讨论】:

以上是关于React Image Preload 和 React-Slick 的错误的主要内容,如果未能解决你的问题,请参考以下文章

ReactNative实现图集功能

preload.ts 中的 contextBridge.exposeInMainWorld:ipcRenderer 接收到来自 main.ts 的消息但渲染器没有得到它

react-native + react-native-tab-navigator 实现 TabBar

页面图片预加载与懒加载

REACT--视频基础组件编写(功能还是比较完善的,采用ES6写法)

JSCSSImage预加载