react-lottie icon indicating copy to clipboard operation
react-lottie copied to clipboard

This library is no longer maintained. Making your own simple wrapper isn't difficult...

Open funwithtriangles opened this issue 3 years ago • 9 comments

If you need something complex, then react-lottie-player looks good. Otherwise the code below is all you need to display a lottie animation on your page. There is no play/pause logic here but that wouldn't be too tricky to add. Just thought I'd post this in case anyone is wondering how much work it will be to get something working themselves.

import { useEffect, useRef } from "react"

import lottie from "lottie-web"

interface LottieProps {
  animationData: any
  width: number
  height: number
}

export const Lottie = ({ animationData, width, height }: LottieProps) => {
  const element = useRef<HTMLDivElement>(null)
  const lottieInstance = useRef<any>()

  useEffect(() => {
    if (element.current) {
      lottieInstance.current = lottie.loadAnimation({
        animationData,
        container: element.current,
      })
    }
    return () => {
      lottieInstance.current?.destroy()
    }
  }, [animationData])

  return <div style={{ width, height }} ref={element}></div>
}

funwithtriangles avatar Jan 26 '22 14:01 funwithtriangles

I was getting this vibe too. Sad to see since it worked fairly well but this is a nice base for a shim. Thank you @funwithtriangles

granolocks avatar Feb 09 '22 22:02 granolocks

Thanks a lot, this works great for most use-cases and is much cleaner.

adrian-burkhart avatar Feb 15 '22 11:02 adrian-burkhart

I'm getting a weird error with this code whereby the animations load twice, any ideas? All I can think of is it's related to the usage of the dependancy array in the useEffct but no idea. Thanks btw!

lclarkg18 avatar Jun 14 '22 00:06 lclarkg18

I'm getting a weird error with this code whereby the animations load twice, any ideas? All I can think of is it's related to the usage of the dependancy array in the useEffct but no idea. Thanks btw!

I tried updating the useEffect a little bit, seems to work fine now.

useEffect(() => {
    if (element.current) {
      lottie.loadAnimation({
        animationData,
        container: element.current,
      });
    }
  }, [animationData]);

SwTan98 avatar Jun 15 '22 08:06 SwTan98

I'm getting a weird error with this code whereby the animations load twice, any ideas? All I can think of is it's related to the usage of the dependancy array in the useEffct but no idea. Thanks btw!

If you're using React 18, useEffect runs twice on mount to make sure the code is idempotent. (only happens in development) And since we are using it to render an animation to the DOM, it explains why this happens.

A workaround is using useRef like this:

const element = useRef(null);
  const lottieInstance = useRef();
  const executeRef = useRef(false);

  useEffect(() => {
    if (executeRef.current) return;
    if (element.current) {
      lottieInstance.current = lottie.loadAnimation({
        animationData,
        loop,
        autoplay,
        container: element.current,
      });
    }
    executeRef.current = true;
  }, []);

evertjr avatar Jun 15 '22 13:06 evertjr

hi,

just a heads up this will leak your instances as it's not actually calling destroy on lottieInstance.current. I'd add something like

  React.useEffect(() => {
    if (element.current) {
      lottieInstance.current?.destroy()
      lottieInstance.current = lottie.loadAnimation({
        animationData,
        container: element.current,
      })
    }
    return () => {
      lottieInstance.current?.destroy()
      lottieInstance.current = null
    }
  }, [animationData])

chrisnojima avatar Jun 28 '22 20:06 chrisnojima

hi,

just a heads up this will leak your instances as it's not actually calling destroy on lottieInstance.current. I'd add something like

  React.useEffect(() => {
    if (element.current) {
      lottieInstance.current?.destroy()
      lottieInstance.current = lottie.loadAnimation({
        animationData,
        container: element.current,
      })
    }
    return () => {
      lottieInstance.current?.destroy()
      lottieInstance.current = null
    }
  }, [animationData])

Good point! I updated my example above. Pretty sure you don't need to have the destroy twice though, the clean up return function will happen before the effect runs every time.

funwithtriangles avatar Jul 05 '22 08:07 funwithtriangles

@funwithtriangles Could you help me get segments to work with this? I can't seem to figure it out. I'm trying to get it to play all frames on the first loop, and then only frames 24-95 on every loop thereafter.

Currently, I have: segments: {[ [0, 23],[24, 95]], true},

jordanlambrecht avatar Aug 08 '22 17:08 jordanlambrecht

@funwithtriangles Could you help me get segments to work with this? I can't seem to figure it out. I'm trying to get it to play all frames on the first loop, and then only frames 24-95 on every loop thereafter.

Currently, I have: segments: {[ [0, 23],[24, 95]], true},

Sorry, I don't know the API very well! I was just posting a simple example that I thought might help others with similar simple needs. If you need anything more complex, then maybe react-lottie-player is more suitable.

funwithtriangles avatar Aug 09 '22 06:08 funwithtriangles