Animated: Stabilize allowlist in useAnimatedPropsMemo (#49140)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/49140

Similar to the change made in `useAnimatedProps`, except for `useAnimatedPropsMemo`. (This is just split out to make the changes easier to review.)

Changelog:
[Internal]

Reviewed By: javache

Differential Revision: D69058338

fbshipit-source-id: 033853673d8fe1442b37bb0c0adc7cb22557c334
This commit is contained in:
Tim Yung
2025-02-03 16:49:40 -08:00
committed by Facebook GitHub Bot
parent 5d4907dde7
commit bc4dee94fe
3 changed files with 43 additions and 34 deletions
@@ -14,7 +14,7 @@ import AnimatedValue from '../../../../Libraries/Animated/nodes/AnimatedValue';
import {
areCompositeKeysEqual,
createCompositeKeyForProps,
} from '../useAnimatedPropsMemo';
} from '../createAnimatedPropsMemoHook';
describe('createCompositeKeyForProps', () => {
describe('with allowlist', () => {
@@ -18,8 +18,8 @@ import AnimatedValue from '../../../Libraries/Animated/nodes/AnimatedValue';
import {isPublicInstance as isFabricPublicInstance} from '../../../Libraries/ReactNative/ReactFabricPublicInstance/ReactFabricPublicInstanceUtils';
import useRefEffect from '../../../Libraries/Utilities/useRefEffect';
import * as ReactNativeFeatureFlags from '../featureflags/ReactNativeFeatureFlags';
import {createAnimatedPropsMemoHook} from './createAnimatedPropsMemoHook';
import NativeAnimatedHelper from './NativeAnimatedHelper';
import {useAnimatedPropsMemo} from './useAnimatedPropsMemo';
import {
useCallback,
useEffect,
@@ -49,6 +49,8 @@ type AnimatedValueListeners = Array<{
export default function createAnimatedPropsHook(
allowlist: ?AnimatedPropsAllowlist,
): AnimatedPropsHook {
const useAnimatedPropsMemo = createAnimatedPropsMemoHook(allowlist);
return function useAnimatedProps<TProps: {...}, TInstance>(
props: TProps,
): [ReducedProps<TProps>, CallbackRef<TInstance | null>] {
@@ -58,7 +60,7 @@ export default function createAnimatedPropsHook(
const node = useAnimatedPropsMemo(
() => new AnimatedProps(props, () => onUpdateRef.current?.(), allowlist),
[allowlist, props],
props,
);
const useNativePropsInFabric =
@@ -48,43 +48,50 @@ type $ReadOnlyCompositeKeyComponent =
| $ReadOnlyArray<$ReadOnlyCompositeKeyComponent | null>
| $ReadOnly<{[string]: $ReadOnlyCompositeKeyComponent}>;
type AnimatedPropsMemoHook = (
() => AnimatedProps,
props: $ReadOnly<{[string]: mixed}>,
) => AnimatedProps;
/**
* A hook that returns an `AnimatedProps` object that is memoized based on the
* subset of `props` that are instances of `AnimatedNode` or `AnimatedEvent`.
* Creates a hook that returns an `AnimatedProps` object that is memoized based
* on the subset of `props` that are instances of `AnimatedNode` or
* `AnimatedEvent`.
*/
export function useAnimatedPropsMemo(
create: () => AnimatedProps,
// TODO: Make this two separate arguments after the experiment is over. This
// is only an array-like structure to make it easier to experiment with this
// and `useMemo`.
[allowlist, props]: [?AnimatedPropsAllowlist, {[string]: mixed}],
): AnimatedProps {
const compositeKey = useMemo(
() => createCompositeKeyForProps(props, allowlist),
[allowlist, props],
);
export function createAnimatedPropsMemoHook(
allowlist: ?AnimatedPropsAllowlist,
): AnimatedPropsMemoHook {
return function useAnimatedPropsMemo(
create: () => AnimatedProps,
props: $ReadOnly<{[string]: mixed}>,
): AnimatedProps {
const compositeKey = useMemo(
() => createCompositeKeyForProps(props, allowlist),
[props],
);
const [state, setState] = useState<{
allowlist: ?AnimatedPropsAllowlist,
compositeKey: $ReadOnlyCompositeKey | null,
value: AnimatedProps,
}>(() => ({
allowlist,
compositeKey,
value: create(),
}));
if (
state.allowlist !== allowlist ||
!areCompositeKeysEqual(state.compositeKey, compositeKey)
) {
setState({
const [state, setState] = useState<{
allowlist: ?AnimatedPropsAllowlist,
compositeKey: $ReadOnlyCompositeKey | null,
value: AnimatedProps,
}>(() => ({
allowlist,
compositeKey,
value: create(),
});
}
return state.value;
}));
if (
state.allowlist !== allowlist ||
!areCompositeKeysEqual(state.compositeKey, compositeKey)
) {
setState({
allowlist,
compositeKey,
value: create(),
});
}
return state.value;
};
}
/**