Issue with flickering scroll-snap in React component with useState

I've encountered an unusual flickering glitch that only occurs when using the combination of:

  • css scroll-snap
  • useState
  • Sub-Components

But it's strange because the issue only arises when these three are combined!

https://i.sstatic.net/TvwyW.gif

Here is a simplified version of the problematic code:

carousel.js

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

export default function Carousel() {
  const [currentScollPos, setCurrentScrollPos] = useState(0)
  const carouselRef = useRef()

  useEffect(() => {
    const carouselScrollUpdate = (e) => {
      setCurrentScrollPos(e.target.scrollLeft)
    }
    carouselRef?.current?.addEventListener('scroll', carouselScrollUpdate, { passive: true })
    return () => {
      carouselRef?.current?.removeEventListener('scroll', carouselScrollUpdate, { passive: true })
    }
  }, [carouselRef])

  const Slide = () => <div className={styles.carouselSlide}>Test Sub</div>
  
  return (
    <div className={styles.carouselInnerContainer} ref={carouselRef}>
      <div className={styles.carouselSlide}>Test1</div>
      <div className={styles.carouselSlide}>Test2</div>
      <div className={styles.carouselSlide}>Test3</div>
      <Slide />
    </div>
  )
}

carousel.module.scss

.carouselInnerContainer {
  display: flex;
  flex-wrap: nowrap;
  overflow-x: scroll;
  scroll-snap-type: x mandatory;
}

.carouselSlide {
  flex: 0 0 auto;
  width: 50%;
  margin-left: 2rem;
  background-color: aquamarine;
  height: 200px;
  scroll-snap-align: center;
}

The flickering issue will NOT occur if I do ONE of the following:

  • comment out:
    setCurrentScrollPos(e.target.scrollLeft)
  • comment out: <Slide />
  • comment out: scroll-snap-align: center; in the CSS

Any insights on this peculiar behavior?

Answer №1

Encountering an issue arises when attempting to update the state each time the scroll position changes

const carouselScrollUpdate = (e) => {
  setCurrentScrollPos(e.target.scrollLeft)
}

Each call to setCurrentScrollPos triggers a re-render of your component, leading to flickering

Instead of updating the state constantly, consider setting the state only when the scrolling stops using setTimeout:

const carouselScrollUpdate = (e) => {      
    clearInterval(timer);
    timer = setTimeout(() => {
        console.log('set scroll')
        setCurrentScrollPos(e.target.scrollLeft)
    }, 500);      
}

Alternatively, you can set the state based on specific conditions:

const carouselScrollUpdate = (e) => {      
    if (isNearNextSlide()) {
      setCurrentScrollPos(e.target.scrollLeft)
    }         
}

const isNearNextSlide = () => {
   // add logic to determine satisfaction of conditions
}

Edit:

After conducting tests, I identified that the problem lies within the nested Slide component inside . I resolved this by relocating the Slide component outside the main Carousel component, avoiding unnecessary recreation of the Slide component during rendering

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

const Slide = () => <div className={styles.carouselSlide}>Test Sub</div>

export default function Carousel() {
  const [currentScollPos, setCurrentScrollPos] = useState(0)
  const carouselRef = useRef()

  useEffect(() => {
    const carouselScrollUpdate = (e) => {
      setCurrentScrollPos(e.target.scrollLeft)
    }
    carouselRef?.current?.addEventListener('scroll', carouselScrollUpdate, { passive: true })
    return () => {
      carouselRef?.current?.removeEventListener('scroll', carouselScrollUpdate, { passive: true })
    }
  }, [carouselRef])
      
  return (
    <div className={styles.carouselInnerContainer} ref={carouselRef}>
      <div className={styles.carouselSlide}>Test1</div>
      <div className={styles.carouselSlide}>Test2</div>
      <div className={styles.carouselSlide}>Test3</div>
      <Slide />
    </div>
  )
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Sorting through various data inputs in one JSON file

I have a JSON file containing an array of objects: obj= [{fname:"abhi",age:5,class:"ten",lanme:"kumar" },{fname:"abhi",age:5,class:"ten",lanme:"kumar" },{fname:"abhi",age:5,class:"t ...

"Enhance user interactions: Zooming in on input fields in

Currently, with the latest version of iOS (14.4), there is a zoom effect on any input box that receives focus, unless the input has a font size of 16px without focus. While this may not seem like an issue initially, once focus moves away from the input bo ...

Intersecting Rays and Positioning Spheres with three.js

I have a scenario where ray intersection is functioning properly with tube geometry. Upon ray intersection, a small red sphere and a tooltip appear next to the cursor. The image below shows the scene without a header: When I include a header using a div e ...

Bootstrap: Arrange multiple images horizontally within a row

I am trying to design a list item for a game that includes a background, an iconholder with an icon, a title, description, and up to three resources. I have been experimenting with Bootstrap and attempted using a container-fluid with an inner row but the i ...

What is the process for verifying which classes have been assigned to a specific component?

I am working with a Vue component and I would like to determine, from within the component itself, which classes have been applied to it. Is there a way to accomplish this? Currently, I am using a workaround where I pass the class as a prop: <my-comp ...

Tips for incorporating a PDF file into a website when the Adobe Reader add-on is disabled in Internet Explorer

I attempted to insert a PDF into my website using the <embed> tag. Unfortunately, it doesn't seem to be functioning properly in Internet Explorer when the Adobe Reader add-on is disabled. Is there a solution that will allow it to work even if th ...

Creating a custom video to use as the favicon for my website

Imagine this: With the help of this plugin, you can have a video playing as your site's favicon using the following code snippet: var favicon=new Favico(); var video=document.getElementById('videoId'); favicon.video(video); //stop favicon.v ...

What is the best way to incorporate a set of buttons and dynamically update them by using next and previous buttons?

Currently, I have code for two sets of buttons. How can we add functionality for next and previous buttons? <div id="chart-section-wrapper" class="container"> <div id="chart-section"> <div class=& ...

When adding margin-left and margin-right, images do not appear in their designated positions

I have a chart displaying images, which are showing up correctly. However, I am facing an issue when I try to add some spacing to the chart by using margin-left and margin-right. Here is the CSS code I included: #chart1 { margin: 0 auto; ...

Is there a mistake in the way I installed create-react-app?

I am eager to experiment with React on my Mac, but I am encountering some challenges along the way. Firstly, I globally installed create-react-app using the command: npm install -g create-react-app However, every time I create a new project, I notice ...

Iterate endlessly over CSS styles in Angular 4

I'm looking to create a website background 'screensaver' by looping through an array of background URLs with a delay between switches. Currently, I have the array stored in my .ts file and I am using the NgFor directive in my HTML. However, ...

The lower div is overlapping the upper div in a smaller viewport

I have integrated some dashboard widgets in iframes and I want to ensure they are responsive. My goal is for each widget to occupy full width when the screen size is reduced, but appear side by side when the browser window is large (md+): iframe { b ...

Adjust the label width to ensure that it aligns correctly with the outlined input field

My current issue involves using a `TextField` with a lengthy label. Despite the label having enough space for the text, it tends to jump to the next line. Check out my codesandbox It seems like the automatic calculation is incorrect, so I am considering ...

Encountering an issue when using the Google authentication provider with Next.js version 13

I am currently working on integrating next-auth with the Google provider and Prisma in my Next.js application, but I encountered the following error: Error: Detected default export in '/MyProject/foodbrain/app/api/auth/[...nextauth]/route.ts'. Pl ...

Storing a webpage in HTML with the use of @import function in CSS

I'm looking to save an entire HTML page, but I'm running into an issue with the CSS file that includes the line: import url('someOtherCss.css'); When attempting to save the page using Firefox or Chrome with 'File->Save Page a ...

What is the best way to integrate the react-simple-captcha canvas element within an MUI Dialog component?

I've recently encountered an issue while trying to integrate react-simple-captcha into the submission form of my React app. The form is nested inside an MUI Dialog component on a specific page. Strangely, when the captcha element is not within a Dialo ...

In the desktop view, the onClick button requires two clicks to trigger the onClick function, while in the mobile view, it only takes one click as expected

Here are the topics I want to display as buttons: const paperTopics = [ "Teaching Aptitude", "Research Aptitude", "Comprehension", "Communication", "Mathematical Reasoning and Aptitude", ...

Adjust the border color of Material UI's DatePicker

https://i.sstatic.net/ZvNOA.png Hello everyone, I am currently working with a DatePicker component from Material UI. My main goal is to change the border color of this component. I have attempted various methods such as modifying classes, adjusting the th ...

Error in NextJS with TypeScript when updating data in a useState variable

Recently, I started working with TypeScript, ReactJS, and NextJS, but I encountered a TypeScript error that I need help fixing. My current project involves using NextJS 14, server actions, and Prisma as the ORM for a university-related project. An issue ar ...

Comparing E-commerce: Laravel's Full MVC Approach vs Next.JS for Dynamic Views

Seeking guidance. Who here is knowledgeable about Next.js (or its rival Nuxt.JS)? In the near future, I have a challenging task of developing a fully customized E-commerce website. This platform needs to be efficient and particularly well optimized for ...