【问题标题】:React doesn't render all images in a listReact 不会渲染列表中的所有图像
【发布时间】:2021-11-30 19:16:08
【问题描述】:

我有 Carousel 组件,它呈现它的孩子并一次显示一个孩子(每个孩子都是一个图像)。该组件由“viewport-div”和“wrapper-div”组成。 Wrapper-div 包含所有图像。为了更改活动图像,我更改了 wrapper-div 的 css-transform。 Carousel 组件采用 'ActiveImage' 属性来定义正在显示的孩子。例如,如果我将 ActiveImage 属性从 x 更改为 y,wrapper-div 会滑动到图像 y,并且我应该能够在此动画期间看到每个图像。但是,当 newprevious ActiveImage 值之间的差异大于 6 时,比如说从 0 到 10,我只能看到 6 个图像,图像 7,8 和 9是不可见的,并且当动画结束时,正在显示图像 10,但仅当屏幕上没有发生任何事情时才会出现此问题,即如果我单击屏幕上的任意位置,按随机键或滚动一切正常。 所有图像都被缩小(~100kb),这就是我导入它们的方式:

export const images = new Array(30).fill(null)

.map((image, number)=>{

    const name = number > 8 ? `${number+1}-min` : `0${number+1}-min`

    return {
        src: process.env.PUBLIC_URL + `/images/min/${name}.jpg`,
        alt:name
    }

})

我认为这与组件逻辑无关,但以防万一这里是代码:

import React, {FC, useEffect, useRef, useState} from 'react';
import styles from './Carousel.module.scss';


type CarouselProps = {
    activeSlideNumber?: number
}


const Carousel: FC<CarouselProps> = ({children, activeSlideNumber}) => {

const [width, setWidth] = useState(0);
const [allowStartDrag, setAllowStartDrag] = useState(true);
const [isDragging, setIsDragging] = useState(false);     // enables carousel move
const [xCoord, setXCoord] = useState(0);
const [currentShift, setCurrentShift] = useState(0);
const [savedShift, setSavedShift] = useState(0);
const [activeSlide, setActiveSlide] = useState(0);

const itemsCount = React.Children.toArray(children).length;

const wrapperRef = useRef<null | HTMLDivElement>(null);  // carousel viewport
const lineRef = useRef<null | HTMLDivElement>(null);     // carousel draggable line

let timeout = null as null | NodeJS.Timeout;

useEffect(()=>{
    if (activeSlideNumber!==undefined) setActiveSlide(activeSlideNumber)
},[activeSlideNumber])

useEffect(() => {

    if (lineRef.current) {

        setAllowStartDrag(false);

        if (timeout) {
            clearTimeout(timeout)
        }

        const slidesPerSweep = Math.abs((currentShift - activeSlide * width) / width);
        const slowDownCoeff = 0.25 * slidesPerSweep;
        setCurrentShift(activeSlide * width);
        setSavedShift(activeSlide*width);

        lineRef.current.style.transition = `transform ${slowDownCoeff}s ease 0s`;
        lineRef.current.style.transform = `translateX(${-activeSlide * width}px)`;

        timeout = setTimeout(() => {

            if (lineRef.current) {
                lineRef.current.style.transition = ``;
            }
            setAllowStartDrag(true);
        }, slowDownCoeff * 1000)
    }

}, [activeSlide])

useEffect(() => {

    if (wrapperRef.current) setWidth(wrapperRef.current.clientWidth)


}, [width])


const onDrag = (e: React.PointerEvent<HTMLDivElement>) => {
    if (!isDragging) return

    const shift = xCoord - e.pageX;

    setCurrentShift(() => {

        if (shift + savedShift < 0) return 0

        if (shift + savedShift > (itemsCount - 1) * width) return (itemsCount - 1) * width

        return shift + savedShift
    });

    e.currentTarget.style.transform = `translate(${-currentShift}px)`;

}

const onSwipeStart = (e: React.PointerEvent) => {
    if (!allowStartDrag) return
    setXCoord(e.pageX);
    setIsDragging(true);
}

const completeSwipe = () => {

        if (currentShift > savedShift ) {
            setActiveSlide(p => p + 1);
        } else if (currentShift < savedShift) {
            setActiveSlide(p => p - 1);
        }

}


const onSwipeEnd = (e: React.PointerEvent) => {
    completeSwipe();
    setIsDragging(false);
}

const onMouseLeave = (e: React.PointerEvent) => {
    completeSwipe();
    setIsDragging(false)
}

return (
    <div className={styles.wrapper} style={{
        width: `${width}px`
    }}>
        <div className={styles.item_line}
             ref={lineRef}
             onPointerDown={onSwipeStart}
             onPointerUp={onSwipeEnd}
             onPointerMove={onDrag}
             onPointerLeave={onMouseLeave}
        >

            {React.Children.toArray(children).map((child, i) => {

                return (
                    <div key={i} ref={i === 0 ? wrapperRef : undefined} className={styles.item}>
                        {child}
                    </div>
                )
            })}
        </div>
        <div className={styles.arrow_left}>
            <button onClick={()=>setActiveSlide(p=> p === 0 ? p : p - 1)}>previous</button>
        </div>
        <div className={styles.arrow_right}>
            <button onClick={()=>setActiveSlide(p=> p === itemsCount - 1 ? p : p + 1)}>next</button>
        </div>
    </div>
);
};

export default Carousel;

我能找到的唯一一些相关的东西是 React Native 渲染错误,但我对 ReactNative 不熟悉,所以希望你能帮助我。

编辑

在动画期间调度事件或更改图像样式不会改变任何内容。只有当我在浏览器中手动单击/滚动/鼠标移动/键入时,错误才会消失(Chrome v.96.0.4664.45)。

在 Firefox v.94.0.1 中一切正常。 在 Opera v.81.0.4196.60 中,很少有图像会在一段时间内消失,几乎看不到。看起来像 Crome 的行为,但是一旦图像消失,它就会再次渲染。 在 Edge v.96.0.1054.34 中,几乎与 Opera 中一样,但“闪烁”的时间要长一些。

对于所有列出的浏览器(Firefox 除外,因为一切正常),在动画期间手动单击/滚动等可以解决问题。

【问题讨论】:

    标签: reactjs image-processing


    【解决方案1】:

    我发现更改页面布局可以解决所有浏览器的问题,所以这是我想出的临时丑陋的解决方案:

    let bugFix = setInterval(() => { // on animation start
                document.body.style.height = `${document.body.clientHeight + 1}px`;
                document.body.style.height = `${document.body.clientHeight - 1}px`;
            }, 500)
    clearInterval(bugFix) // on animation end
    

    注意:结果取决于延迟值。如果延迟足够长以至于浏览器停止渲染图像,问题仍然存在。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-12-21
      • 1970-01-01
      • 2020-09-28
      • 2011-04-21
      • 2020-12-07
      • 1970-01-01
      • 1970-01-01
      • 2017-01-04
      相关资源
      最近更新 更多