UNPKG

react-native-reanimated

Version:

More powerful alternative to Animated library for React Native.

119 lines (110 loc) 4.12 kB
'use strict'; import { isWorkletFunction } from 'react-native-worklets'; import { IS_WEB, logger, ReanimatedError } from '../common'; // Builds one big hash from multiple worklets' hashes. export function buildWorkletsHash(worklets) { // For arrays `Object.values` returns the array itself. return Object.values(worklets).reduce((acc, worklet) => acc + worklet.__workletHash.toString(), ''); } // Builds dependencies array for useEvent handlers. export function buildDependencies(dependencies, handlers) { const result = dependencies ?? []; const nonWorkletHandlerNames = Object.entries(handlers).reduce((acc, [name, handler]) => { if (!isWorkletFunction(handler)) { acc.push(name); } return acc; }, []); if (nonWorkletHandlerNames.length === 0) { result.push(buildWorkletsHash(handlers)); return result; } if (!__DEV__) { return result; } const handlerNames = nonWorkletHandlerNames.join(', '); // On native, only worklets are allowed if (!IS_WEB) { throw new ReanimatedError(`Passed handlers that are not worklets. Only worklet functions are allowed. Handlers "${handlerNames}" are not worklets.`); } // On web, non-worklets are allowed only when dependencies are provided if (__DEV__ && !dependencies) { logger.warn(`Non-worklet handlers ("${handlerNames}") were passed without a dependency array. This will cause the hook to update on every render. Please provide a dependency array or use only worklet functions instead.`); return undefined; } return result; } function areWorkletsEqual(worklet1, worklet2) { if (worklet1.__workletHash === worklet2.__workletHash) { const closure1Keys = Object.keys(worklet1.__closure); const closure2Keys = Object.keys(worklet2.__closure); return closure1Keys.length === closure2Keys.length && closure1Keys.every(key => key in worklet2.__closure && worklet1.__closure[key] === worklet2.__closure[key]); } return false; } // This is supposed to work as useEffect comparison. export function areDependenciesEqual(nextDependencies, prevDependencies) { function is(x, y) { return x === y && (x !== 0 || 1 / x === 1 / y) || Number.isNaN(x) && Number.isNaN(y); } const objectIs = typeof Object.is === 'function' ? Object.is : is; function areHookInputsEqual(nextDeps, prevDeps) { if (!nextDeps || !prevDeps || prevDeps.length !== nextDeps.length) { return false; } for (let i = 0; i < prevDeps.length; ++i) { const nextDep = nextDeps[i]; const prevDep = prevDeps[i]; if (objectIs(nextDep, prevDep)) { continue; } if (!isWorkletFunction(nextDep) || !isWorkletFunction(prevDep)) { return false; } if (!areWorkletsEqual(nextDep, prevDep)) { return false; } } return true; } return areHookInputsEqual(nextDependencies, prevDependencies); } export function isAnimated(prop) { 'worklet'; if (Array.isArray(prop)) { return prop.some(isAnimated); } else if (typeof prop === 'object' && prop !== null) { if (prop.onFrame !== undefined) { return true; } else { return Object.values(prop).some(isAnimated); } } return false; } // This function works because `Object.keys` // return empty array of primitives and on arrays // it returns array of its indices. export function shallowEqual(a, b) { 'worklet'; const aKeys = Object.keys(a); const bKeys = Object.keys(b); if (aKeys.length !== bKeys.length) { return false; } for (let i = 0; i < aKeys.length; i++) { if (a[aKeys[i]] !== b[aKeys[i]]) { return false; } } return true; } export function validateAnimatedStyles(styles) { 'worklet'; if (typeof styles !== 'object') { throw new ReanimatedError(`\`useAnimatedStyle\` has to return an object, found ${typeof styles} instead.`); } else if (Array.isArray(styles)) { throw new ReanimatedError('`useAnimatedStyle` has to return an object and cannot return static styles combined with dynamic ones. Please do merging where a component receives props.'); } } //# sourceMappingURL=utils.js.map