Add animation queue to modern createAnimatedComponent

Summary:
Add animation queuing back into createAnimatedComponent_EXPERIMENTAL.js, which is a concurrent-safe version of createAnimatedComponent.

T93269035 for details on why this is needed.

# How does this work?

In the old createAnimatedComponent, Animations were queued by calling `setWaitingForIdentifier` before render, and then calling `unsetWaitingForIdentifier` after render.

In this diff, instead we are calling `setWaitingForIdentifier` in an `useLayoutEffect` before calling `useAnimatedProps`, and we are calling `unsetWaitingForIdentifier` in a `useEffect` after `useAnimatedProps`. So the ordering for the effects are:

1. `useLayoutEffect` with `setWaiting`
2. `useLayoutEffect`s in `useAnimatedProps`
3. `useEffect`s in `useAnimatedProps`
4. `useEffect` with `unsetWaiting`.

There's a React guarantee that **if one effect is called, all of them will be called**, so we don't have a concern about the queue getting locked.

## **Main concerns:**
1. This works in my test cases, but it's not the same behavior as the old createAnimatedComponent (which is wait before and unset wait after render). This may still be ok because the relevant side effects in render from that component have been moved to `useLayoutEffect` or `useEffect` in `useAnimatedProps` (so the ordering is still the same?).
2. I'm not sure about the ordering of `onLayoutEffect`, `onLayout` callbacks, and `useEffect`. createAnimatedComponent_EXPERIMENTAL doesn't use `onLayout`, but with this new method of queuing, **`onLayout` calls will likely be called before the animation queue has been flushed**. It's not clear to me whether this is bad.

Changelog: [Internal]

Reviewed By: yungsters

Differential Revision: D29467458

fbshipit-source-id: 2be23a8968404526d0fa394a7879fda8b5ffbfdc
This commit is contained in:
Kacie Bawiec 2021-07-08 09:28:18 -07:00 коммит произвёл Facebook GitHub Bot
Родитель bc1e602e0c
Коммит 7ebafc0066
1 изменённых файлов: 24 добавлений и 1 удалений

Просмотреть файл

@ -13,7 +13,16 @@
import AnimatedProps from './nodes/AnimatedProps'; import AnimatedProps from './nodes/AnimatedProps';
import {AnimatedEvent} from './AnimatedEvent'; import {AnimatedEvent} from './AnimatedEvent';
import useRefEffect from '../Utilities/useRefEffect'; import useRefEffect from '../Utilities/useRefEffect';
import {useCallback, useLayoutEffect, useMemo, useReducer, useRef} from 'react'; import NativeAnimatedHelper from './NativeAnimatedHelper';
import {
useCallback,
useEffect,
useLayoutEffect,
useMemo,
useReducer,
useRef,
useState,
} from 'react';
type ReducedProps<TProps> = { type ReducedProps<TProps> = {
...TProps, ...TProps,
@ -22,6 +31,8 @@ type ReducedProps<TProps> = {
}; };
type CallbackRef<T> = T => mixed; type CallbackRef<T> = T => mixed;
let animatedComponentNextId = 1;
export default function useAnimatedProps<TProps: {...}, TInstance>( export default function useAnimatedProps<TProps: {...}, TInstance>(
props: TProps, props: TProps,
): [ReducedProps<TProps>, CallbackRef<TInstance | null>] { ): [ReducedProps<TProps>, CallbackRef<TInstance | null>] {
@ -129,6 +140,18 @@ function useAnimatedPropsLifecycle(node: AnimatedProps): void {
const prevNodeRef = useRef<?AnimatedProps>(null); const prevNodeRef = useRef<?AnimatedProps>(null);
const isUnmountingRef = useRef<boolean>(false); const isUnmountingRef = useRef<boolean>(false);
const [animatedComponentId] = useState(
() => `${animatedComponentNextId++}:animatedComponent`,
);
useLayoutEffect(() => {
NativeAnimatedHelper.API.setWaitingForIdentifier(animatedComponentId);
});
useEffect(() => {
NativeAnimatedHelper.API.unsetWaitingForIdentifier(animatedComponentId);
});
useLayoutEffect(() => { useLayoutEffect(() => {
isUnmountingRef.current = false; isUnmountingRef.current = false;
return () => { return () => {