Search code examples
reactjsreact-hooksswipe

How to avoid re-rendering with react-swipe library and useState


I am using a react library for swiping: https://github.com/voronianski/react-swipe Making it work is straight-forward:

import React, {useEffect, useState} from 'react';
import ReactDOM from 'react-dom';
import ReactSwipe from 'react-swipe'
import styled from 'styled-components'

const StyledBox = styled.div`
  height: 50px;
  width: 100%;
  background-color: orange;
`

const Carousel = () => {
  let reactSwipeEl;

  const [position, setPosition] = useState(0)
  console.log('position', position)

  const swipeOptions = {
    continuous: false,
    transitionEnd() {
      setPosition(reactSwipeEl.getPos())
    }
  }

  return (
    <div>
      <ReactSwipe
        className="carousel"
        swipeOptions={swipeOptions}
        ref={el => (reactSwipeEl = el)}
      >
        <StyledBox>PANE 1</StyledBox>
        <StyledBox>PANE 2</StyledBox>
        <StyledBox>PANE 3</StyledBox>
      </ReactSwipe>
      <Circles>
        <Circle isActive={0 === position} />
        <Circle isActive={1 === position}/>
      </Circles>
    </div>
  );
};

export default Carousel

The code that I added is the one related with useState. The library works fine, but every time I swipe, I use the callback transitionEnd, in order to update the position state. It is updated, but since a state variable changes, the whole Carousel component gets updated, setting automatically the init value, which is 0.

I don't understand how can I avoid this problem which is, updating the state without re-rendering the whole component. Should I split it in two components and use a provider? I tried it, but when the state of the provider changes, both components are also re-render


Solution

  • The swipeOptions is recreated on each render, which causes the ReactSwipe to rerender as well. Wrap the swipeOptions with useMemo() (sandbox);

    const swipeOptions = useMemo(() => ({
      continuous: false,
      transitionEnd() {
        setPosition(reactSwipeEl.current.getPos())
      }
    }), []);