Skip to content

Commit

Permalink
fix(🐎): improved Reanimated wrapper (#2379)
Browse files Browse the repository at this point in the history
  • Loading branch information
wcandillon committed Apr 18, 2024
1 parent 0294341 commit aeb5a85
Show file tree
Hide file tree
Showing 13 changed files with 110 additions and 151 deletions.
2 changes: 1 addition & 1 deletion example/src/Examples/API/AnimatedImages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
Image,
useAnimatedImageValue,
} from "@shopify/react-native-skia";
import { useSharedValue } from "@shopify/react-native-skia/src/external/reanimated/moduleWrapper";
import { useSharedValue } from "react-native-reanimated";

export const AnimatedImages = () => {
const { width: wWidth } = useWindowDimensions();
Expand Down
7 changes: 5 additions & 2 deletions example/src/Examples/FrostedCard/FrostedCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ import {
import React from "react";
import { Dimensions, View } from "react-native";
import { Gesture, GestureDetector } from "react-native-gesture-handler";
import { useSharedValue, withSpring } from "react-native-reanimated";
import { useDerivedValue } from "@shopify/react-native-skia/src/external/reanimated/moduleWrapper";
import {
useSharedValue,
withSpring,
useDerivedValue,
} from "react-native-reanimated";

import { BlurMask } from "./BlurGradient";

Expand Down
7 changes: 5 additions & 2 deletions fabricexample/src/Examples/FrostedCard/FrostedCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ import {
import React from "react";
import { Dimensions, View } from "react-native";
import { Gesture, GestureDetector } from "react-native-gesture-handler";
import { useSharedValue, withSpring } from "react-native-reanimated";
import { useDerivedValue } from "@shopify/react-native-skia/src/external/reanimated/moduleWrapper";
import {
useSharedValue,
withSpring,
useDerivedValue,
} from "react-native-reanimated";

import { BlurMask } from "./BlurGradient";

Expand Down
27 changes: 27 additions & 0 deletions package/src/external/ModuleProxy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// https://github.com/mrousavy/react-native-vision-camera/blob/main/package/src/dependencies/ModuleProxy.ts
type ImportType = ReturnType<typeof require>;

/**
* Create a lazily-imported module proxy.
* This is useful for lazily requiring optional dependencies.
*/
export const createModuleProxy = <TModule>(
name: string,
getModule: () => ImportType
): TModule => {
const holder: { module: TModule | undefined } = { module: undefined };

const proxy = new Proxy(holder, {
get: (target, property) => {
if (target.module == null) {
try {
target.module = getModule() as TModule;
} catch (e) {
throw new Error(`${name} is not installed!`);
}
}
return target.module[property as keyof typeof holder.module];
},
});
return proxy as unknown as TModule;
};
14 changes: 14 additions & 0 deletions package/src/external/reanimated/ReanimatedProxy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type * as ReanimatedT from "react-native-reanimated";

import { createModuleProxy } from "../ModuleProxy";
type TReanimated = typeof ReanimatedT;

const Reanimated = createModuleProxy<TReanimated>(
"react-native-reanimated",
() => {
return require("react-native-reanimated");
}
);

// eslint-disable-next-line import/no-default-export
export default Reanimated;
13 changes: 7 additions & 6 deletions package/src/external/reanimated/buffers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@ import type { WorkletFunction } from "react-native-reanimated/lib/typescript/rea
import type { SkColor, SkHostRect, SkPoint, SkRSXform } from "../../skia/types";
import { Skia } from "../../skia";

import { startMapper, stopMapper, makeMutable } from "./moduleWrapper";
import { notifyChange } from "./interpolators";
import Rea from "./ReanimatedProxy";

type Modifier<T> = (input: T, index: number) => void;

const useBufferValue = <T>(size: number, bufferInitializer: () => T) =>
useMemo(
() => makeMutable(new Array(size).fill(0).map(bufferInitializer)),
const useBufferValue = <T>(size: number, bufferInitializer: () => T) => {
return useMemo(
() => Rea.makeMutable(new Array(size).fill(0).map(bufferInitializer)),
// eslint-disable-next-line react-hooks/exhaustive-deps
[size]
);
};

const useBuffer = <T>(
size: number,
Expand All @@ -24,7 +25,7 @@ const useBuffer = <T>(
const values = useBufferValue(size, bufferInitializer);
const mod = modifier as WorkletFunction;
const deps = [size, ...Object.values(mod.__closure ?? {})];
const mapperId = startMapper(() => {
const mapperId = Rea.startMapper(() => {
"worklet";
values.value.forEach((val, index) => {
modifier(val, index);
Expand All @@ -34,7 +35,7 @@ const useBuffer = <T>(

useEffect(() => {
return () => {
stopMapper(mapperId);
Rea.stopMapper(mapperId);
};
}, [mapperId]);

Expand Down
19 changes: 7 additions & 12 deletions package/src/external/reanimated/interpolators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,7 @@ import { interpolatePaths, interpolateVector } from "../../animation";
import { Skia } from "../../skia";
import { isOnMainThread } from "../../renderer/Offscreen";

import {
useAnimatedReaction,
useFrameCallback,
useSharedValue,
useDerivedValue,
} from "./moduleWrapper";
import Rea from "./ReanimatedProxy";

export const notifyChange = (value: SharedValue<unknown>) => {
"worklet";
Expand All @@ -27,8 +22,8 @@ export const notifyChange = (value: SharedValue<unknown>) => {

export const usePathValue = (cb: (path: SkPath) => void, init?: SkPath) => {
const pathInit = useMemo(() => Skia.Path.Make(), []);
const path = useSharedValue(pathInit);
useDerivedValue(() => {
const path = Rea.useSharedValue(pathInit);
Rea.useDerivedValue(() => {
path.value.reset();
if (init !== undefined) {
path.value.addPath(init);
Expand All @@ -40,15 +35,15 @@ export const usePathValue = (cb: (path: SkPath) => void, init?: SkPath) => {
};

export const useClock = () => {
const clock = useSharedValue(0);
const clock = Rea.useSharedValue(0);
const callback = useCallback(
(info: FrameInfo) => {
"worklet";
clock.value = info.timeSinceFirstFrame;
},
[clock]
);
useFrameCallback(callback);
Rea.useFrameCallback(callback);
return clock;
};

Expand All @@ -73,8 +68,8 @@ const useInterpolator = <T>(
) => {
// eslint-disable-next-line react-hooks/exhaustive-deps
const init = useMemo(() => factory(), []);
const result = useSharedValue(init);
useAnimatedReaction(
const result = Rea.useSharedValue(init);
Rea.useAnimatedReaction(
() => value.value,
(val) => {
result.value = interpolator(val, input, output, options, result.value);
Expand Down
83 changes: 0 additions & 83 deletions package/src/external/reanimated/moduleWrapper.ts

This file was deleted.

49 changes: 31 additions & 18 deletions package/src/external/reanimated/renderHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,39 @@ import type { Container } from "../../renderer/Container";
import type { AnimatedProps } from "../../renderer/processors";
import type { Node } from "../../dom/types";

import {
startMapper,
stopMapper,
isSharedValue,
HAS_REANIMATED3,
HAS_REANIMATED2,
runOnJS,
} from "./moduleWrapper";
import Rea from "./ReanimatedProxy";

let HAS_REANIMATED = false;
let HAS_REANIMATED_3 = false;
try {
require("react-native-reanimated");
HAS_REANIMATED = true;
const reanimatedVersion =
require("react-native-reanimated/package.json").version;
if (
reanimatedVersion &&
(reanimatedVersion >= "3.0.0" || reanimatedVersion.includes("3.0.0-"))
) {
HAS_REANIMATED_3 = true;
}
} catch (e) {
HAS_REANIMATED = false;
}

const _bindings = new WeakMap<Node<unknown>, unknown>();

export const unbindReanimatedNode = (node: Node<unknown>) => {
if (!HAS_REANIMATED) {
return;
}
const previousMapperId = _bindings.get(node);
if (previousMapperId !== undefined) {
stopMapper(previousMapperId as number);
Rea.stopMapper(previousMapperId as number);
}
};

export function extractReanimatedProps(props: AnimatedProps<any>) {
if (!HAS_REANIMATED3 && !HAS_REANIMATED2) {
if (!HAS_REANIMATED) {
return [props, {}];
}
const reanimatedProps = {} as AnimatedProps<any>;
Expand All @@ -33,7 +46,7 @@ export function extractReanimatedProps(props: AnimatedProps<any>) {
continue;
}
const propValue = props[propName];
if (isSharedValue(propValue)) {
if (Rea.isSharedValue(propValue)) {
reanimatedProps[propName] = propValue;
otherProps[propName] = propValue.value;
} else {
Expand All @@ -51,7 +64,7 @@ function bindReanimatedProps2(
const sharedValues = Object.values(reanimatedProps);
const previousMapperId = _bindings.get(node);
if (previousMapperId !== undefined) {
stopMapper(previousMapperId as number);
Rea.stopMapper(previousMapperId as number);
}
if (sharedValues.length > 0) {
const viewId = container.getNativeId();
Expand All @@ -70,9 +83,9 @@ function bindReanimatedProps2(
container.redraw();
}
};
const mapperId = startMapper(() => {
const mapperId = Rea.startMapper(() => {
"worklet";
runOnJS(updateProps)();
Rea.runOnJS(updateProps)();
}, sharedValues);
_bindings.set(node, mapperId);
}
Expand All @@ -83,21 +96,21 @@ export function bindReanimatedProps(
node: Node<any>,
reanimatedProps: AnimatedProps<any>
) {
if (HAS_REANIMATED2 && !HAS_REANIMATED3) {
if (HAS_REANIMATED && !HAS_REANIMATED_3) {
return bindReanimatedProps2(container, node, reanimatedProps);
}
if (!HAS_REANIMATED3) {
if (!HAS_REANIMATED) {
return;
}
const sharedValues = Object.values(reanimatedProps);
const previousMapperId = _bindings.get(node);
if (previousMapperId !== undefined) {
stopMapper(previousMapperId as number);
Rea.stopMapper(previousMapperId as number);
}
if (sharedValues.length > 0) {
const viewId = container.getNativeId();
const { SkiaViewApi } = global;
const mapperId = startMapper(() => {
const mapperId = Rea.startMapper(() => {
"worklet";
if (node) {
for (const propName in reanimatedProps) {
Expand Down
6 changes: 3 additions & 3 deletions package/src/external/reanimated/textures.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
} from "../../renderer/Offscreen";
import { Skia, useImage } from "../../skia";

import { runOnUI, useSharedValue } from "./moduleWrapper";
import Rea from "./ReanimatedProxy";

const createTexture = (
texture: SharedValue<SkImage | null>,
Expand Down Expand Up @@ -57,10 +57,10 @@ export const usePictureAsTexture = (
picture: SkPicture | null,
size: SkSize
) => {
const texture = useSharedValue<SkImage | null>(null);
const texture = Rea.useSharedValue<SkImage | null>(null);
useEffect(() => {
if (picture !== null) {
runOnUI(createTexture)(texture, picture, size);
Rea.runOnUI(createTexture)(texture, picture, size);
}
}, [texture, picture, size]);
return texture;
Expand Down
Loading

0 comments on commit aeb5a85

Please sign in to comment.