ShareChat
Moj

Jeet11: React swipeable screens - One of the smallest and most effective library

Ashutosh Tanwar

Ashutosh Tanwar7 Sept, 2022

Follow us on FacebookFollow us on TwitterFollow us on InstagramFollow us on Linkedin
Jeet11: React swipeable screens - One of the smallest and most effective library

Animations in PWA give a more native feel to the users, but smooth animations are still challenging in even the most popular PWA apps as we know that they are WebApps and the browser has to handle all the computations.

We faced a similar challenge with our application, Jeet11, which runs on mobile devices and supports a lot of low-end devices.
We tried using react-swipeable-views and a few other libraries on the web, which were, to an extent, solving the problem but not as we had required like the following:

  • High performance: No sloppy animation even on low-end mobile devices.
  • Library size < 10kB.
  • Fully customizable in terms of content and design props.
  • Selected tab highlighting. Check out this here.
  • Supports blocked swipe area: Users can indicate non-swipeable areas within the swipeable content.

Demo

So, how have we enhanced the performance?

Firstly, Whenever we want to display something on the web page, the browser has to go through some sequential steps:

  1. Style: Calculating the styles.
  2. Layout: Generates the geometry and position.
  3. Paint: Filling or painting the pixels into layers.
  4. Composite: Draws all the layers to the screen.

During animations, the browser repeats some or all of the above steps in sequence; hence animating something that changes layout is more expensive than animating something that only changes compositing.

Secondly, to our problem of making swipeable slides we could use different CSS properties like marginLeft, Left, and Absolute, or the one we used the transform property.

Transform does not trigger any geometry changes or painting; this means the operation can be carried out by the compositor thread instead of the javascript main thread, resulting in a smooth transition without a lag.

Comparison between animations using different CSS properties:

Using Transform

Using Top/Left

Pro Tip: To check the effectiveness of your animations all you have to do is,
Open the dev tool > More tools > Rendering > Then check the Paint flashing and Layout Shift Region boxes.

Thirdly, we used window.requestAnimationFrame() method that tells the browser you wish to perform an animation and the browser can optimize concurrent animations together into a single reflow and repaint cycle.

Ways of performing Animation:

Older Way

1
2
3
setInterval(() =>  {
  // animate something
}, (1000/60));

Newer Way

1
2
3
4
5
function repeatOften() {
  // animate something
  requestAnimationFrame(repeatOften);
}
requestAnimationFrame(repeatOften);

The number of callbacks (repeatOften) usually matches the display refresh rate in web browsers, i.e., 60 frames per second, to put this in purview:
The browser has (1000/60 ~ 16.67) milliseconds to execute scripts, recalculate styles, layout and repaint the updated area.

CSS animations, transitions, and transform properties generally use the browser’s rendering engine, and to force the browser to use GPU for better performance we can translate3d instead of translateX.
Also using will-change: transform will ensure the browser applies optimizations for future changes.

Here is the performance comparison between react-swipeable-views and our library with different parameters and CPU throttling using the chrome dev tool.


*We compared both libraries in the same environment. These numbers may differ on a different machine. Recorded the performance by swiping the slide after the first mount.
Machine Specs: MacBook Pro (16-inch, 2021), Apple M1 Pro Chip, 16 GB Memory


Usage

Install the package using yarn or npm

$ npm install --save @mohalla-tech/react-swipeable-wrapper

Here the example usage:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import SwipeableWrapper from "react-swipeable-wrapper";

...
  const swipeRef = useRef(null);
  const bottomBarRef = useRef(null);
  const tabNames = ["Tab 1", "Tab 2", "Tab 3"];

  const onTabClick = useCallback(currentIndex => {
    const { getCurrentIndex, swipeToIndex } = swipeRef?.current ?? {};
    const previousIndex = getCurrentIndex();
    if (currentIndex !== previousIndex) swipeToIndex(currentIndex);
  }, []);

  return (
    <div>
        <div style={styles.tabsParent}>
          <div style={styles.tabs}>
            {tabNames.map((tab, index) => (
              <span key={tab} onClick={() => onTabClick(index)}>
                {tab}
              </span>
            ))}
          </div>
          <div ref={bottomBarRef} style={styles.bottomBar} />
        </div>
        <SwipeableWrapper
          initialIndex={0}
          ref={swipeRef}
          bottomBarRef={bottomBarRef}
        >
          <div style={styles.slide1}>1st slide</div>
          <div style={styles.slide2}>2nd slide</div>
          <div style={styles.slide3}>3rd slide</div>
        </SwipeableWrapper>
    </div>
  );
...


Note: initialIndex should be memoized using React.useMemo() or a constant value.

We are hiring!

At ShareChat, we believe in keeping our Bharat users entertained in their language of preference. We are revolutionizing how India consumes content and the best in class Engineering technology is at the forefront of this transformation. In addition, you'll also get the opportunity to work on some of the most complex problems at scale while creating an impact on the broader content creation ecosystem.

Exciting? You can check out various open roles here!




Other Suggested Blog

Are you in search of a job profile that fits your skill set perfectly?

Congratulations! You’ve reached the right place!

We are enroute to building a team of humble, yet ambitious folks. Grow professionally in your career with us, as we offer tremendous room for growth in unique career fields. Do not miss out on this unique opportunity. Send us your resume today!