@@ -37,6 +37,7 @@ export default function useAnimatedProps<TProps: {...}, TInstance>(
3737) : [ ReducedProps < TProps > , CallbackRef < TInstance | null > ] {
3838 const [ , scheduleUpdate ] = useReducer < number , void> ( count => count + 1 , 0 ) ;
3939 const onUpdateRef = useRef < ?( ) => void > ( null ) ;
40+ const timerRef = useRef < TimeoutID | null > ( null ) ;
4041
4142 // TODO: Only invalidate `node` if animated props or `style` change. In the
4243 // previous implementation, we permitted `style` to override props with the
@@ -87,6 +88,25 @@ export default function useAnimatedProps<TProps: {...}, TInstance>(
8788 // $FlowIgnore[not-a-function] - Assume it's still a function.
8889 // $FlowFixMe[incompatible-use]
8990 instance . setNativeProps ( node . __getAnimatedValue ( ) ) ;
91+ if ( isFabricInstance ( instance ) ) {
92+ // Keeping state of Fiber tree and Shadow tree in sync.
93+ //
94+ // This is done by calling `scheduleUpdate` which will trigger a commit.
95+ // However, React commit is not fast enough to drive animations.
96+ // This is where setNativeProps comes in handy but the state between
97+ // Fiber tree and Shadow tree needs to be kept in sync.
98+ // The goal is to call `scheduleUpdate` as little as possible to maintain
99+ // performance but frequently enough to keep state in sync.
100+ // Debounce is set to 48ms, which is 3 * the duration of a frame.
101+ // 3 frames was the highest value where flickering state was not observed.
102+ if ( timerRef . current != null ) {
103+ clearTimeout ( timerRef . current ) ;
104+ }
105+ timerRef . current = setTimeout ( ( ) => {
106+ timerRef . current = null ;
107+ scheduleUpdate ( ) ;
108+ } , 48 ) ;
109+ }
90110 }
91111 } ;
92112
0 commit comments