@shopify/react-native-skia
Version:
High-performance React Native Graphics using Skia
104 lines (91 loc) • 2.79 kB
text/typescript
import { useEffect, useRef, useState } from "react";
import { Skia } from "../Skia";
import type { SkData, DataSourceParam, SkJSIInstance } from "../types";
import { Platform } from "../../Platform";
const factoryWrapper = <T>(
data2: SkData,
factory: (data: SkData) => T,
onError?: (err: Error) => void
) => {
const factoryResult = factory(data2);
if (factoryResult === null) {
onError && onError(new Error("Could not load data"));
return null;
} else {
return factoryResult;
}
};
export const loadData = <T>(
source: DataSourceParam,
factory: (data: SkData) => T | null,
onError?: (err: Error) => void
): Promise<T | null> => {
if (source === null || source === undefined) {
return new Promise((resolve) => resolve(null));
} else if (source instanceof Uint8Array) {
return new Promise((resolve) =>
resolve(factoryWrapper(Skia.Data.fromBytes(source), factory, onError))
);
} else {
const uri =
typeof source === "string" ? source : Platform.resolveAsset(source);
return Skia.Data.fromURI(uri).then((d) =>
factoryWrapper(d, factory, onError)
);
}
};
const useLoading = <T extends SkJSIInstance<string>>(
source: DataSourceParam,
loader: () => Promise<T | null>
) => {
const mounted = useRef(false);
const [data, setData] = useState<T | null>(null);
const dataRef = useRef<T | null>(null);
useEffect(() => {
mounted.current = true;
loader().then((value) => {
if (mounted.current) {
setData(value);
dataRef.current = value;
}
});
return () => {
mounted.current = false;
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [source]);
return data;
};
export const useCollectionLoading = <T extends SkJSIInstance<string>>(
source: DataSourceParam[],
loader: () => Promise<(T | null)[]>
) => {
const mounted = useRef(false);
const [data, setData] = useState<T[] | null>(null);
const dataRef = useRef<T[] | null>(null);
useEffect(() => {
mounted.current = true;
loader().then((result) => {
const value = result.filter((r) => r !== null) as T[];
if (mounted.current) {
setData(value);
dataRef.current = value;
}
});
return () => {
mounted.current = false;
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [source]);
return data;
};
export const useRawData = <T extends SkJSIInstance<string>>(
source: DataSourceParam,
factory: (data: SkData) => T | null,
onError?: (err: Error) => void
) => useLoading(source, () => loadData<T>(source, factory, onError));
const identity = (data: SkData) => data;
export const useData = (
source: DataSourceParam,
onError?: (err: Error) => void
) => useRawData(source, identity, onError);