1

So I have an animation using React Native Reanimated that repeats every 3 seconds and updates the SharedValue. I have implemented it as shown below using setInterval.

const SomeThreshold = 5;

useEffect(() => {
  progress.value = 0;

  const interval = setInterval(() => {
    if (progress.value === SomeThreshold) {
      progress.value = 0;
      return;
    }

    progress.value = withTiming(progress.value + 1, {
      duration: 2000,
    });
  }, 3000);

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

What I want to achieve is

-> Animation Starts

-> Progress = 1

-> Progress = 2

-> Progress = 3

-> Progress = 4

-> Progress = 5

-> Progress = 1

-> Progress = 2

and this goes on infinitely.

Is there any way to implement it without using Web APIs like setInterval and maybe using withRepeat.

Kartikey
  • 4,516
  • 4
  • 15
  • 40

1 Answers1

1

You should be able to use a combination of:

  • withRepeat, a Reanimated function that repeats an animation a specified number of times or infinitely: in your case, using -1, infinitely.
  • withSequence, another Reanimated function that runs the provided animations in a sequence: in your case, from 1 to 5.

That would be (from the discussion):

const SomeThreshold = 5;

const Example = () => {
  const progress = useSharedValue(0);

  useEffect(() => {
    progress.value = withRepeat(
      withSequence(
        withTiming(0), 
        ...Array(SomeThreshold)
          .fill(0)
          .map((_, i) => withTiming(i + 1, {duration: 2000 })),
      ),
      -1,
    );
  }, []);

// ...
};

The idea is to use Array(SomeThreshold).fill(0).map((_, i) => withTiming(i + 1, {duration: 3000})) to create an array of withTiming animations that will update the progress value from 1 to SomeThreshold, with each update taking 3 seconds.

The .map((_, i) => withTiming(i + 1, {duration: 3000})) part maps over the array and for each element creates a withTiming animation that updates the progress value to i + 1.

Combined with withRepeat(withSequence(...), -1), that would repeat infinitely.

withSequence takes in 2 parameters:

  • First: an animation.
  • Second: an array (iterable) of animations.
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • Woah..The idea looks good. It's just that typescript is complaining that `A spread argument must either have a tuple type or be passed to a rest parameter.` for the `withSequence` statement. Any solution for that? – Kartikey Mar 07 '23 at 07:27
  • @Kartikey Possibly using an array literal should help. See my edited answer. – VonC Mar 07 '23 at 07:34
  • The progress.value expects a number, but with this implementation, it will return a number[]. Typescript complain `Type 'number[]' is not assignable to type 'number'.` – Kartikey Mar 07 '23 at 07:38
  • @Kartikey Good point. For testing, can you try instead using [`Animated.sequence(`](https://reactnative.dev/docs/animated#sequence) instead of `withSequence([` (so no more array): By using `Animated.sequence()`, you would create a single animation that runs the animations in sequence, which can be assigned to `progress.value` without encountering a type mismatch error. – VonC Mar 07 '23 at 07:43
  • Can you please add the code snippet for that (`Animated.sequence()` version) in the answer? – Kartikey Mar 07 '23 at 07:50
  • Hey @VonC, `Animated.sequence` comes from `react-native` and not `react-native-reanimated` and also `AnimatableValue` and `SharedValue` are different. This doesn't work. Any other way to achieve this? – Kartikey Mar 07 '23 at 08:00
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/252340/discussion-between-vonc-and-kartikey). – VonC Mar 07 '23 at 08:11