Animating React with Finesse

Nikhil Sharma, SDE II Postman

Hey, I'm Nikhil 👋

I love to talk about performance, react and design systems

nik72619c

 

          niksharma1997

"Everything that you do is an animation"

Why do the frames drop?

There's a deadline to produce each frame...

1000ms/60fps = 16.7ms per frame
let myBox = document.querySelector('.my-box');

if (myBox) {
  myBox.classList.add('my-special-box')
}

1

oh, something changed! I need to generate a new frame.

3

I need to calculate how much space they take on the screen and where they should be positioned

5

 Now, I should combine these bitmaps in the defined order to form the final frame.

2

now I must apply class my-special-class to to that <div> element).

4

 I should group elements (that have an output) in multiple layers and convert each layer into a bitmap representation in the memory or the video RAM.

1

JS evaluation

3

Layout

5

Composition

2

Style calculation

4

Paint

Which is ...

Why do we need to know all this?

Optimised pipeline = optimised animations

#1: Avoid reflows

Avoid the CSS properties that cause recalculations like display, instead use visibility or opacity

.element {
     opacity: 1;
     transition: .3s;
}
 .element.closed {
     opacity: 0;
     pointer-events: none;
}

Make elements paint-ready

the will-change property lets the browser know which elements are paint-expensive.

.box { will-change: auto;}

Optimising JS Animations

setInterval()

useEffect(() => {
    const intervalId = setInterval(() => {
      if (circleRef.current) {
        position += speed * direction;

        if (position >= distance || position <= 0) {
          direction *= -1;
        }

        circleRef.current.style.transform = `translateX(${position}px)`;

        // Additional work to make the setInterval animation more intensive
        for (let i = 0; i < 10000000; i++) {}
      }
    }, 16); // Roughly 60fps

    return () => clearInterval(intervalId);
  }, []);

setInterval()

  • Does not guarantee running at the start of each call
  • Runs on the main thread

Missed frame train wagons

             😓

requestAnimationFrame()

useEffect(() => {
    const animate = () => {
      if (circleRef.current) {
        position += speed * direction;

        if (position >= distance || position <= 0) {
          direction *= -1;
        }

        circleRef.current.style.transform = `translateX(${position}px)`;

        // Additional work to make the animation more intensive
        for (let i = 0; i < 10000000; i++) {}

        requestAnimationFrame(animate);
      }
    };

    requestAnimationFrame(animate);

    return () => cancelAnimationFrame(animate);
  }, []);

requestAnimationFrame()

  • Functions are run at the start instead
  • Runs when the browser is ready to paint
  • Auto-optimised resource management

CSS is better than js?

  • Hardware-accelarated
  • Runs on compositor-thread
  • Browser-controlled
  • Complex animations

CSS is better than js?

useEffect(() => {
    const circle = circleRef.current;
    if (circle) {
      circle.animate(
        [{ transform: "translateX(0)" }, { transform: "translateX(200px)" }],
        {
          duration: 2000,
          iterations: Infinity,
          direction: "alternate",
        }
      );
    }
  }, []);
.circle {
  width: 50px;
  height: 50px;
  background-color: blue;
  border-radius: 50%;
  position: relative;
  animation: moveCircle 2s infinite alternate;
}

@keyframes moveCircle {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(200px);
  }
}

CSS

Web Animation API

=

Using libraries

They are battle-tested, apply all such performance optimisations out of the box

import React from 'react';
import { motion } from 'framer-motion';

const CircleAnimationFramerMotion = () => {
  return (
    <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh' }}>
      <motion.div
        animate={{ x: [0, 200, 0] }}
        transition={{ duration: 2, repeat: Infinity, repeatType: 'reverse' }}
        style={{
          width: '50px',
          height: '50px',
          backgroundColor: 'red',
          borderRadius: '50%',
        }}
      ></motion.div>
    </div>
  );
};

export default CircleAnimationFramerMotion;

Efficiency is doing things right; effectiveness is doing the right things.

– Peter Drucker

Intersection Observer API

useEffect(() => {
    const observer = new IntersectionObserver(
      (entries) => {
        entries.forEach((entry) => {
          setIsIntersecting(entry.isIntersecting);
        });
      },
      { threshold: 0.1 } // Adjust the threshold as needed
    );

    if (circleRef.current) {
      observer.observe(circleRef.current);
    }

    return () => {
      if (circleRef.current) {
        observer.unobserve(circleRef.current);
      }
    };
  }, []);

getBoundingClientRect()

Avoid recalculations

items.forEach((item) => {
  item.style.transform =
    "translateY(" + container.getBoundingClientRect().height + "px)";
});

 // VS

const containerHeight = container.getBoundingClientRect().height + "px";
items.forEach((item) => {
  item.style.transform = "translateY(" + containerHeight + "px)";

Debounce and throtlling

const throttleTime = 100;
function onScroll(event) {
  if (Date.now() > prevTime + throttleTime) {
    callback();
  }
}

window.addEventListener("scroll", onScroll);
  • Pixel pipeline
  • Using the lighter css styles
  • Optimising js animations using requestAnimationFrame
  • Using CSS animations + web API
  • Avoiding redundant work

Quick recap!

Important Links

Thank You!

Questions?

Process

During the ideation phase, expect to discuss the project in depth to clearly understand the goals and requirements.

1

Ideation

Our team makes each part of the build phase seamless with regular check-ins and deliverables.

2

Build

It's time to take the product live - the end if the build phase but the beginning of being in market.

3

Launch

Philosophy

Once all is removed that can be removed, that is how designs are truly in their simplest form.

Meet the Team

CFO

George

CEO

Elaine

Advisor

Susan

Our Services

We offer a variety of services and plans tailored to business needs of any kind and of any size.

  • Thoughtful process
  • Dedicated team
  • Pixel-perfect work
  • 24/7 support

ACME

Competitors

  • Fragmented workflow
  • Too many clients
  • Rushed deliveries
  • 9-5 support

1

Discovery of requirements for a project.

3

Creating a Plan that sets the requirements for the design and build phases.

5

Build the project to an MVP to test and evaluate. Iterate using these learnings.

2

Research into the project space, competitors and the market.

4

Review and Iterate on the designs with testing of ideas, client feedback and prototypes.

  • Conceptualization
  • Product Design
  • Development
  • UI/UX Testing
  • Branding

Our Services

ACME Offices

Country City Contact
USA Los Angeles +1 555 0194
USA New York +1 555 0142
Sweden Stockholm +46 555 0077
UK London +44 555 0211
South Korea Seoul +82 555 0138

The Summit is what drives us, but the climb itself is what matters.

– Conrad Anker

Available 24/7

Contact us via email or phone

Photo by Raimond Klavins

ACME Design Inc started a two-person operation in 2011. In their hometown of Los Angeles, California, the founders came together with a vision to design and build beautiful, simple web and mobile products.

In ten years, the team has grown to over one hundred members with offices in four countries. In that time the goal has always remained the same: to design impactful solutions to complex problems.

Our Story

Thank You!

Questions?

Palette

By nik72619c

Palette

  • 68