0

I'm currently learning React Native and I have been stuck on my component for several hours. It is an image swipe system. I know there are a lot of packages that do what I want, but I'd rather create my own system to learn better.

Here is the description of my problem: The first swipe works perfectly well but each time I swipe the user interface freezes for a second and I can't figure out why.

Here you can try my code : https://snack.expo.dev/-1yjXbe4M

import { useEffect, useState } from "react";
import {
  Text,
  View,
  Dimensions,
  Image,
  Animated,
  PanResponder,
} from "react-native";

const SCREEN_HEIGHT = Dimensions.get("window").height;
const SCREEN_WIDTH = Dimensions.get("window").width;

const GetMovies = () => {
  return [
    {
      poster_path: "/gOnmaxHo0412UVr1QM5Nekv1xPi.jpg",
    },
    {
      poster_path: "/vZloFAK7NmvMGKE7VkF5UHaz0I.jpg",
    },
    {
      poster_path: "/kuf6dutpsT0vSVehic3EZIqkOBt.jpg",
    },
    {
      poster_path: "/x3PIk93PTbxT88ohfeb26L1VpZw.jpg",
    },
    {
      poster_path: "/zCdzPK6fJgQL0FeKeYkciZzjyOL.jpg",
    },
    {
      poster_path: "/sv1xJUazXeYqALzczSZ3O6nkH75.jpg",
    },
    {
      poster_path: "/dm06L9pxDOL9jNSK4Cb6y139rrG.jpg",
    },
    {
      poster_path: "/t6HIqrRAclMCA60NsSmeqe9RmNV.jpg",
    },
    {
      poster_path: "/qi9r5xBgcc9KTxlOLjssEbDgO0J.jpg",
    },
    {
      poster_path: "/aCy61aU7BMG7SfhkaAaasS0KzUO.jpg",
    },
    {
      poster_path: "/3GrRgt6CiLIUXUtoktcv1g2iwT5.jpg",
    },
    {
      poster_path: "/kUWTY8rwEZ3d8G31GuPMbvqS67D.jpg",
    },
    {
      poster_path: "/v5CfpzxoJDkZxjZAizClFdlEF0U.jpg",
    },
    {
      poster_path: "/hrATQE8ScQceohwInaMluluNEaf.jpg",
    },
  ];
};

const Swiper = () => {
  const [movies, setMovies] = useState([]);
  const [currentIndex, setCurrentIndex] = useState(0);
  const position = new Animated.ValueXY();

  useEffect(() => {
    setMovies(GetMovies());
  }, []);

  useEffect(() => {
    position.setValue({ x: 0, y: 0 });
  }, [currentIndex]);

  const rotate = position.x.interpolate({
    inputRange: [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2],
    outputRange: ["-10deg", "0deg", "10deg"],
    extrapolate: "clamp",
  });

  const panResponder = PanResponder.create({
    onStartShouldSetPanResponder: (evt, gestureState) => true,
    onPanResponderMove: (evt, gestureState) => {
      position.setValue({ x: gestureState.dx, y: gestureState.dy });
    },
    onPanResponderRelease: (evt, gestureState) => {
      if (gestureState.dx > 120) {
        Animated.spring(position, {
          toValue: { x: SCREEN_WIDTH + 100, y: gestureState.dy },
          useNativeDriver: true,
        }).start(() => {
          setCurrentIndex(currentIndex + 1);
        });
      } else if (gestureState.dx < -120) {
        Animated.spring(position, {
          toValue: { x: -SCREEN_WIDTH - 100, y: gestureState.dy },
          useNativeDriver: true,
        }).start(() => {
          setCurrentIndex(currentIndex + 1);
        });
      } else {
        Animated.spring(position, {
          toValue: { x: 0, y: 0 },
          friction: 4,
          useNativeDriver: true,
        }).start();
      }
      console.log("PanResponder release");
    },
  });

  const rotateAndTranslate = {
    transform: [
      {
        rotate: rotate,
      },
      ...position.getTranslateTransform(),
    ],
  };

  const likeOpacity = position.x.interpolate({
    inputRange: [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2],
    outputRange: [0, 0, 1],
    extrapolate: "clamp",
  });

  const nopeOpacity = position.x.interpolate({
    inputRange: [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2],
    outputRange: [1, 0, 0],
    extrapolate: "clamp",
  });

  const nextCardOpacity = position.x.interpolate({
    inputRange: [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2],
    outputRange: [1, 0, 1],
    extrapolate: "clamp",
  });

  const nextCardScale = position.x.interpolate({
    inputRange: [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2],
    outputRange: [1, 0.8, 1],
    extrapolate: "clamp",
  });

  return (
    <View style={{ flex: 1 }}>
      {console.log("rendering")}
      <View style={{ height: 60 }} />
      <View style={{ flex: 1 }}>
        {movies &&
          movies
            .map((item, i) => {
              console.log(item);
              if (i < currentIndex) {
                return null;
              } else if (i == currentIndex) {
                return (
                  <Animated.View
                    {...panResponder.panHandlers}
                    key={i}
                    style={[
                      rotateAndTranslate,
                      {
                        height: SCREEN_HEIGHT - 120,
                        width: SCREEN_WIDTH,
                        padding: 10,
                        position: "absolute",
                      },
                    ]}
                  >
                    <Animated.View
                      style={{
                        opacity: likeOpacity,
                        transform: [{ rotate: "-30deg" }],
                        position: "absolute",
                        top: 50,
                        left: 40,
                        zIndex: 1000,
                      }}
                    >
                      <Text
                        style={{
                          borderWidth: 1,
                          borderColor: "green",
                          color: "green",
                          fontSize: 32,
                          fontWeight: "800",
                          padding: 10,
                        }}
                      >
                        GAUCHE
                      </Text>
                    </Animated.View>
                    <Animated.View
                      style={{
                        opacity: nopeOpacity,
                        transform: [{ rotate: "30deg" }],
                        position: "absolute",
                        top: 50,
                        right: 40,
                        zIndex: 1000,
                      }}
                    >
                      <Text
                        style={{
                          borderWidth: 1,
                          borderColor: "red",
                          color: "red",
                          fontSize: 32,
                          fontWeight: "800",
                          padding: 10,
                        }}
                      >
                        DROITE
                      </Text>
                    </Animated.View>
                    <Image
                      style={{
                        flex: 1,
                        height: null,
                        width: null,
                        resizeMode: "cover",
                        borderRadius: 20,
                      }}
                      source={{
                        uri: `https://image.tmdb.org/t/p/w200${item.poster_path}`,
                      }}
                    />
                  </Animated.View>
                );
              } else {
                return (
                  <Animated.View
                    key={i}
                    style={{
                      opacity: nextCardOpacity,
                      transform: [{ scale: nextCardScale }],
                      height: SCREEN_HEIGHT - 120,
                      width: SCREEN_WIDTH,
                      padding: 10,
                      position: "absolute",
                    }}
                  >
                    <Image
                      style={{
                        flex: 1,
                        height: null,
                        width: null,
                        resizeMode: "cover",
                        borderRadius: 20,
                      }}
                      source={{
                        uri: `https://image.tmdb.org/t/p/w200${item.poster_path}`,
                      }}
                    />
                  </Animated.View>
                );
              }
            })
            .reverse()}
      </View>
    </View>
  );
};

export default Swiper;
Hapax
  • 31
  • 4

0 Answers0