Search code examples
javascriptreactjssettimeoutsetintervalreact-spring

How can I use setInterval() to automatically change slides on this React Spring project


I implemented this React Spring component that gets a different slide after clicking on it. I would like to make it change automatically every X seconds by using the setInterval method.

I tried using setInterval but I'm not getting the desired results, because the setInterval function gets called multiple times and as the time increases the slides start changing like crazy until the browser freezes.

Here's the codesandbox original project https://codesandbox.io/embed/1y3yyqpq7q

And here's the code that I'm running currently

import { useTransition, animated } from 'react-spring'
import clientStyles from '../../styles/modules_scss/clients.module.scss'

const pages = [
    ({ style }) => <animated.div style={{ ...style, background: 'lightpink' }}>Andres Mejias</animated.div>,
    ({ style }) => <animated.div style={{ ...style, background: 'lightblue' }}>Andres Urdaneta</animated.div>,
    ({ style }) => <animated.div style={{ ...style, background: 'lightgreen' }}>Gustavo Abdelnour</animated.div>,
]

export default function SlideTransition() {
    const [index, set] = useState(0)
    const onClick = useCallback(() => set(state => (state + 1) % 3), [])
    const transitions = useTransition(index, p => p, {
        from: { opacity: 0, transform: 'translate3d(100%,0,0)' },
        enter: { opacity: 1, transform: 'translate3d(0%,0,0)' },
        leave: { opacity: 0, transform: 'translate3d(-50%,0,0)' },
    })
    return (
        <div className={clientStyles.simpleTransMain} onClick={setInterval(onClick, 3000)}> //Here's my approach
            {transitions.map(({ item, props, key }) => {
                const Page = pages[item]
                return <Page key={key} style={props} />
            })}
        </div>
    )
}

The best result I got was by wrapping setInterval in a anonymous function, and AFTER clicking the first slide I get a new slide every 3000ms. I want this to happen without the need of clicking on the slide, as soon as the page loads.

onClick={() => { setInterval(onClick, 3000) }}


Solution

  • You are calling setInterval on every render so a new interval is getting created each time and your first one is still running. So you just get more and more added until it overloads the browser.

    Since you want the interval to start before anything is clicked, add it to an effect so you can run it when the app mounts and clear it on unmount.

    useEffect(() => {
      const interval_id = setInterval(onClick, 3000);
       return () => {
         // Stop the interval when the component unmounts. 
         // Otherwise it will keeep going and you will get an error.
         clearInterval(interval_id)
       }
    }, []); // empty array of dependencies will cause it to run on mount and unmount only
    

    Then just remove the setInterval in the onClick and you should be good to go.