How to add image preloading animation to a react native component using reanimated2
Tags: javascript, reactnative, react
Published: 2021-12-29 09:18:19

Hello, how about we make our react native app a little bit fancy by adding preloading animations to our image component using the awesome <a href="https://docs.swmansion.com/react-native-reanimated/" >reanimated2 library</a>

We'll wrap the the Image component in an animated view having the same dimension as the image and create a state to manage the image status.
```ts
import React, { useEffect, useState } from "react";
import Animated, {
  interpolateColor,
  useAnimatedStyle,
  useSharedValue,
  withTiming,
} from "react-native-reanimated";

interface Props {
  /**base64 string or url for the image */
  uri: string;
  width: number;
  height: number;
}
const AppImage = ({ height, uri, width }: Props) => {
  const [isImageLoading, setIsImageLoading] = useState(true);

  return (
    <Animated.View style={[{ width, height }]}>
      <Animated.Image
        {...{ height, width, source: { uri } }}
        style={[{ width, height }]
        resizeMethod="auto"
        resizeMode="cover"
      />
    </Animated.View>
  );
};

export default AppImage;
```

The image opacity  will be set to 0 on mounting while we animated the background of the animated view with a loop animation
When the image is loaded, we'll stop the loop animation and set the image opacity to 1

```ts
import React, { useEffect, useState } from "react";
import Animated, {
  interpolateColor,
  useAnimatedStyle,
  useSharedValue,
  withTiming,
} from "react-native-reanimated";

interface Props {
  /**base64 string or url for the image */
  uri: string;
  width: number;
  height: number;
}
const AppImage = ({ height, uri, width }: Props) => {
  const [isImageLoading, setIsImageLoading] = useState(true);
  const loop = useSharedValue(0); // this will be used to control the animation of the image container

  const animatedContainerStyle = useAnimatedStyle(() => ({
    backgroundColor: interpolateColor(loop.value, [0, 1], ["black", "white"]), // animate the background color of the image container
  }));

  const animatedImageStyle = useAnimatedStyle(() => ({
    opacity: withTiming(isImageLoading ? 0 : 1, { duration: 500 }), // fade in image when loaded
  }));

  useEffect(() => {
    let animationInterval: NodeJS.Timeout;

    //start animation when the component mounts
    animationInterval = setInterval(() => {
      loop.value = withTiming(loop.value === 1 ? 0 : 1, { duration: 500 });
    }, 250);

    //stop animation when the image is loaded
    !isImageLoading && clearInterval(animationInterval);
    return () => clearInterval(animationInterval); //cleanup
  }, [isImageLoading]);

  return (
    <Animated.View style={[{ width, height }, animatedContainerStyle]}>
      <Animated.Image
        {...{ height, width, source: { uri } }}
        style={[{ width, height }, animatedImageStyle]}
        onLoad={(e) => {
          setIsImageLoading(false);
        }}
        resizeMethod="auto"
        resizeMode="cover"
      />
    </Animated.View>
  );
};

export default AppImage;
```
Here is a preview

![Preview](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7ba8szb1wttmlm01utri.gif)