Skip to content

Instantly share code, notes, and snippets.

@christianbaroni
Last active May 16, 2024 03:56
Show Gist options
  • Save christianbaroni/32cbb096f89dc544478f4a5cca951f34 to your computer and use it in GitHub Desktop.
Save christianbaroni/32cbb096f89dc544478f4a5cca951f34 to your computer and use it in GitHub Desktop.
/* eslint-disable @typescript-eslint/no-explicit-any */
import { DerivedValue, SharedValue, runOnJS, useAnimatedReaction } from 'react-native-reanimated';
import { deepEqualWorklet, shallowEqualWorklet } from '@/worklets/comparisons';
interface BaseSyncParams<T> {
/** The depth of comparison for object values. @default 'deep' */
compareDepth?: 'shallow' | 'deep';
/** A derived value or shared value that controls whether the synchronization should be paused. */
pauseSync?: DerivedValue<boolean> | SharedValue<boolean>;
/** The JS state to be synchronized. */
state: T | undefined;
}
interface SharedToStateParams<T> extends BaseSyncParams<T> {
/** The setter function for the JS state (only applicable when `syncDirection` is `'sharedValueToState'`). */
setState: (value: T) => void;
/** The shared value to be synchronized. */
sharedValue: DerivedValue<T | undefined> | SharedValue<T | undefined>;
/** The direction of synchronization. */
syncDirection: 'sharedValueToState';
}
interface StateToSharedParams<T> extends BaseSyncParams<T> {
setState?: never;
/** The shared value to be synchronized. */
sharedValue: SharedValue<T | undefined>;
/** The direction of synchronization. */
syncDirection: 'stateToSharedValue';
}
type SyncParams<T> = SharedToStateParams<T> | StateToSharedParams<T>;
/**
* ### useSyncSharedValue
*
* Synchronizes a shared value with a piece of JS state in the specified direction.
*
* @param {SyncParams<T>} config - Configuration options for synchronization:
* - `compareDepth` - The depth of comparison for object values. Default is `'deep'`.
* - `pauseSync` - A derived value or shared value that controls whether synchronization is paused.
* - `setState` - The setter function for the JS state (only applicable when `syncDirection` is `'sharedValueToState'`).
* - `sharedValue` - The shared value to be synchronized.
* - `state` - The JS state to be synchronized.
* - `syncDirection` - The direction of synchronization.
*
* @example
* const [state, setState] = useState(0);
* const sharedValue = useSharedValue(0);
*
* useSyncSharedValue({
* setState,
* sharedValue,
* state,
* syncDirection: 'sharedValueToState',
* });
*/
export function useSyncSharedValue<T>({ compareDepth = 'deep', pauseSync, setState, sharedValue, state, syncDirection }: SyncParams<T>) {
useAnimatedReaction(
() => {
if (pauseSync?.value) {
return false;
}
if (typeof sharedValue.value === 'object' && sharedValue.value !== null && typeof state === 'object' && state !== null) {
const isEqual =
compareDepth === 'deep'
? deepEqualWorklet(sharedValue.value as Record<string, any>, state as Record<string, any>)
: shallowEqualWorklet(sharedValue.value as Record<string, any>, state as Record<string, any>);
return !isEqual;
}
return sharedValue.value !== state;
},
shouldSync => {
if (shouldSync) {
if (syncDirection === 'sharedValueToState' && sharedValue.value !== undefined) {
runOnJS(setState)(sharedValue.value);
} else if (syncDirection === 'stateToSharedValue') {
sharedValue.value = state;
}
}
}
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment