From 0d59eec8ef36f32bc23f1e024cdbe24545abc90a Mon Sep 17 00:00:00 2001 From: Kevin Detter <99418257+oikalyptus@users.noreply.github.com> Date: Fri, 25 Sep 2026 20:35:23 +0200 Subject: [PATCH 1/2] fix: Stop passing useDerivedValue dependencies on native (#613) --- .../useAnimatableValue.dependencies.test.ts | 44 +++++++++++++++++++ .../reanimated/hooks/useAnimatableValue.ts | 14 ++++-- 2 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 packages/react-native-sortables/src/integrations/reanimated/hooks/useAnimatableValue.dependencies.test.ts diff --git a/packages/react-native-sortables/src/integrations/reanimated/hooks/useAnimatableValue.dependencies.test.ts b/packages/react-native-sortables/src/integrations/reanimated/hooks/useAnimatableValue.dependencies.test.ts new file mode 100644 index 00000000..10d768b9 --- /dev/null +++ b/packages/react-native-sortables/src/integrations/reanimated/hooks/useAnimatableValue.dependencies.test.ts @@ -0,0 +1,44 @@ +import { renderHook } from '@testing-library/react-hooks'; +import { useDerivedValue } from 'react-native-reanimated'; + +import useAnimatableValue from './useAnimatableValue'; + +let mockIsWeb = false; + +jest.mock('react-native-reanimated', () => ({ + isSharedValue: jest.fn(() => false), + useDerivedValue: jest.fn(() => ({ value: 0 })) +})); + +jest.mock('../../../constants', () => ({ + get IS_WEB() { + return mockIsWeb; + } +})); + +describe(useAnimatableValue, () => { + const mockUseDerivedValue = jest.mocked(useDerivedValue); + + it('does not pass dependencies to useDerivedValue on native, where Reanimated warns about them', () => { + mockIsWeb = false; + + renderHook(() => useAnimatableValue(1)); + + expect(mockUseDerivedValue).toHaveBeenCalledWith( + expect.any(Function), + undefined + ); + }); + + it('passes the value and modifier as dependencies on web, where Reanimated needs them', () => { + mockIsWeb = true; + const modify = (value: number) => value * 2; + + renderHook(() => useAnimatableValue(1, modify)); + + expect(mockUseDerivedValue).toHaveBeenCalledWith(expect.any(Function), [ + 1, + modify + ]); + }); +}); diff --git a/packages/react-native-sortables/src/integrations/reanimated/hooks/useAnimatableValue.ts b/packages/react-native-sortables/src/integrations/reanimated/hooks/useAnimatableValue.ts index 65dc9f4a..7823192a 100644 --- a/packages/react-native-sortables/src/integrations/reanimated/hooks/useAnimatableValue.ts +++ b/packages/react-native-sortables/src/integrations/reanimated/hooks/useAnimatableValue.ts @@ -4,6 +4,7 @@ import type { SharedValue } from 'react-native-reanimated'; import { isSharedValue, useDerivedValue } from 'react-native-reanimated'; +import { IS_WEB } from '../../../constants'; import type { Animatable } from '../types'; export default function useAnimatableValue( @@ -19,8 +20,13 @@ export default function useAnimatableValue any>( value: Animatable, modify?: F ): SharedValue> | SharedValue { - return useDerivedValue(() => { - const inputValue = isSharedValue(value) ? value.value : value; - return modify ? modify(inputValue) : inputValue; - }, [value, modify]); + // Reanimated only uses dependencies on web and warns about them on native, where they are + // derived from the worklet closure + return useDerivedValue( + () => { + const inputValue = isSharedValue(value) ? value.value : value; + return modify ? modify(inputValue) : inputValue; + }, + IS_WEB ? [value, modify] : undefined + ); } From a245fe93f6137917dbbba9b029707688599f99b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20=C5=81opaci=C5=84ski?= Date: Sat, 26 Sep 2026 13:06:24 +0200 Subject: [PATCH 2/2] Import IS_WEB from constants/platform to avoid circular dependencies --- .../reanimated/hooks/useAnimatableValue.dependencies.test.ts | 2 +- .../src/integrations/reanimated/hooks/useAnimatableValue.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-native-sortables/src/integrations/reanimated/hooks/useAnimatableValue.dependencies.test.ts b/packages/react-native-sortables/src/integrations/reanimated/hooks/useAnimatableValue.dependencies.test.ts index 10d768b9..21541391 100644 --- a/packages/react-native-sortables/src/integrations/reanimated/hooks/useAnimatableValue.dependencies.test.ts +++ b/packages/react-native-sortables/src/integrations/reanimated/hooks/useAnimatableValue.dependencies.test.ts @@ -10,7 +10,7 @@ jest.mock('react-native-reanimated', () => ({ useDerivedValue: jest.fn(() => ({ value: 0 })) })); -jest.mock('../../../constants', () => ({ +jest.mock('../../../constants/platform', () => ({ get IS_WEB() { return mockIsWeb; } diff --git a/packages/react-native-sortables/src/integrations/reanimated/hooks/useAnimatableValue.ts b/packages/react-native-sortables/src/integrations/reanimated/hooks/useAnimatableValue.ts index 7823192a..031a36a9 100644 --- a/packages/react-native-sortables/src/integrations/reanimated/hooks/useAnimatableValue.ts +++ b/packages/react-native-sortables/src/integrations/reanimated/hooks/useAnimatableValue.ts @@ -4,7 +4,7 @@ import type { SharedValue } from 'react-native-reanimated'; import { isSharedValue, useDerivedValue } from 'react-native-reanimated'; -import { IS_WEB } from '../../../constants'; +import { IS_WEB } from '../../../constants/platform'; import type { Animatable } from '../types'; export default function useAnimatableValue(