Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export let getViewInfo = (element: any) => {
return getViewInfo73(element);
};

// This gets invoked on Paper on 0.76
function getViewInfo73(element: any) {
return {
// we can access view tag in the same way it's accessed here https://github.com/facebook/react/blob/e3f4eb7272d4ca0ee49f27577156b57eeb07cf73/packages/react-native-renderer/src/ReactFabric.js#L146
Expand Down
38 changes: 37 additions & 1 deletion packages/react-native-reanimated/src/hook/useAnimatedStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import type { MutableRefObject } from 'react';
import { useEffect, useRef } from 'react';

import { makeShareable, startMapper, stopMapper } from '../core';
import { makeShareable, runOnUI, startMapper, stopMapper } from '../core';
import updateProps, { updatePropsJestWrapper } from '../UpdateProps';
import { initialUpdaterRun } from '../animation';
import { useSharedValue } from './useSharedValue';
Expand Down Expand Up @@ -35,6 +35,7 @@ import type {
} from '../commonTypes';
import { isWorkletFunction } from '../commonTypes';
import { ReanimatedError } from '../errors';
import { Platform } from 'react-native';

const SHOULD_BE_USE_WEB = shouldBeUseWeb();

Expand All @@ -43,6 +44,7 @@ interface AnimatedState {
animations: AnimatedStyle<any>;
isAnimationRunning: boolean;
isAnimationCancelled: boolean;
isFirstRun: boolean;
}

interface AnimatedUpdaterData {
Expand Down Expand Up @@ -465,6 +467,7 @@ For more, see the docs: \`https://docs.swmansion.com/react-native-reanimated/doc
animations: {},
isAnimationCancelled: false,
isAnimationRunning: false,
isFirstRun: true,
}),
viewDescriptors: makeViewDescriptorsSet(),
};
Expand Down Expand Up @@ -511,11 +514,44 @@ For more, see the docs: \`https://docs.swmansion.com/react-native-reanimated/doc
areAnimationsActive,
isAnimatedProps
);
if (
Platform.OS === 'android' &&
!globalThis._IS_FABRIC &&
remoteState.isFirstRun
) {
/*
This is a makeshift patch for a bug on Paper Android.

When an Animated Component gets mounted and it already has an
update (i.e. animation starts on mount), the first update can be
lost. This is due to fact that Android UIManager is batching the
Native Views creation - an update might come before such batch
is executed, in result trying to modify a view which doesn't exist.

After failing to force the UIManager
to create the View pre-update, I decided to instead schedule the
first update twice for Animated Style, because on another
frame the view should exist and the update should be successful.
*/
requestAnimationFrame(() =>
styleUpdater(
shareableViewDescriptors,
updater,
remoteState,
areAnimationsActive,
isAnimatedProps
)
);
Comment on lines +536 to +544
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should consider resolving this in native code - similar to the fixes we've already implemented for iOS:

The current solution seems a bit undeterministic and could potentially cause some unexpected blinking 🤔

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly I don't believe it would lead to blinks, since the update is never stale - but probably during some heavy traffic and slow JS/UI the update could still get lost (although a lot less likely).

Implementing it in the native code is the best solution here, but then it's a code that would need to be maintained and it steers us away from improving Reanimated for Fabric 😿

remoteState.isFirstRun = false;
}
};
}
const mapperId = startMapper(fun, inputs);
return () => {
stopMapper(mapperId);
if (Platform.OS === 'android' && !globalThis._IS_FABRIC) {
runOnUI(() => (remoteState.isFirstRun = true))();
}
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, dependencies);
Expand Down