Performance issue with very fast setState calls in React?

Viewed 1285

I've created a simple draggable component. I'm using the react-swipeable library but my question is about any event which repeatedly and in quick succession updates useState.

With the console.log in onSwiping I can see that the function is called many times per second, which is what I need to update the position of the component. This works however is there a performance issue with calling setSwipeX so frequently?

The entire component will re-render very fast as it's dragged. Is this OK or would it be better to just update swipeX without re-rendering the entire component, and is this even possible?

import React from "react";
import { useSwipeable } from "react-swipeable";

export default function App() {
  const [swipeX, setSwipeX] = React.useState(0);

  const swipeHandlers = useSwipeable({
    onSwiping: (e) => {
      console.log(e);
      setSwipeX(-e.deltaX);
    },
    trackMouse: true
  });

  return (
    <div
      className="App"
      {...swipeHandlers}
      style={{
        transform: `translateX(${swipeX}px)`
      }}
    >
      <h1>Stuff</h1>
    </div>
  );
}

https://codesandbox.io/s/relaxed-minsky-ni7n9?file=/src/App.js

2 Answers

I'm not an expert when it comes to performance, but I have implemented a couple of weeks ago a component that lets you swipe down page component. It was very similar to what you were doing, but vertically. First time I tried to do so with useState, I had no issues on my Pixel 3a. But when I tested it on Nexus 5x, it wasn't smooth at all. When I changed the logic to work with useRef instead of userState, it felt much smoother. Something like this:

import React from "react";
import { useSwipeable } from "react-swipeable";

export default function App() {
  const ref = React.useRef(null);

  const swipeHandlers = useSwipeable({
    onSwiping: (e) => {
      console.log(e);
      ref.style.transform = `translateX(${-e.deltaX}px)`;
    },
    trackMouse: true
  });

  return (
    <div
      className="App"
      {...swipeHandlers}
      ref={ref}
    >
      <h1>Stuff</h1>
    </div>
  );
}

This way, you change the DOM directly. As mentioned again, I didn't test it by numbers, but physically on a low end device I could see a bit of difference.

The use of useState in the above example is necessary to achieve the desired functionality of tracking mouse movement.

Through my experience, I found that repeated calls to useState do not cause performance problems. In fact, the useState is one of the primary advantages of using React that provides better performance than any other method of repeated calls.

On the other hand, through my experience, I found the following:

  1. Repeated calls to useEffect can have serious impact on performance.

  2. Repeated calls to useState can impact memory consumption, if the state object is a complex data structure that holds lot of information (Several KB of data)

The above example invokes useState repeatedly. However, the state object is simple and very small (one variable that consumes only a few bytes of memory).

Also, in the above example, there is no usage of the often resource guzzling useEffect.

Therefore, the repeated calls to useState will not have any performance impact in the above scenario.

Related