Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save SwarajDashDev/4a48f39200e85511b7e26b552dd2d0a0 to your computer and use it in GitHub Desktop.

Select an option

Save SwarajDashDev/4a48f39200e85511b7e26b552dd2d0a0 to your computer and use it in GitHub Desktop.
Use React's useSyncExternalStore hook to bridge UI state between the JavaScript thread and Reanimated worklets, eliminating flicker and ensuring deterministic updates.

Insight

React 18 introduced useSyncExternalStore to provide a reliable subscription model for external data sources. In React Native, you can exploit this hook to keep UI components in sync with Reanimated worklets that run on the UI thread. By exposing a tiny store that both the JS thread and the worklet can read, you avoid the classic "state lag" when animating based on async data.

Example

// store.ts
import { EventEmitter } from 'events';
export const uiStore = new EventEmitter();
export let value = 0;
export const setValue = (v: number) => {
  value = v;
  uiStore.emit('change');
};

// Component.tsx
import { useSyncExternalStore } from 'react';
import { uiStore, value } from './store';
import { useSharedValue, useDerivedValue, runOnJS } from 'react-native-reanimated';

export default function Counter() {
  const count = useSyncExternalStore(
    (cb) => uiStore.on('change', cb),
    () => value
  );
  const sv = useSharedValue(count);
  sv.value = count; // UI thread sees the latest value instantly
  return <Text>{sv.value}</Text>;
}

Takeaway

Wrap any mutable value in a tiny EventEmitter‑based store and read it with useSyncExternalStore. This guarantees that both the JS thread and Reanimated worklets see the same snapshot, eliminating UI jitter without pulling in a full state‑management library.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment