UNPKG

4.15 kBPlain TextView Raw
1'use strict';
2import { shouldBeUseWeb } from './PlatformChecker';
3import type { Mutable } from './commonTypes';
4import { makeShareableCloneRecursive } from './shareables';
5import { shareableMappingCache } from './shareableMappingCache';
6import { executeOnUIRuntimeSync, runOnUI } from './threads';
7import { valueSetter } from './valueSetter';
8
9const SHOULD_BE_USE_WEB = shouldBeUseWeb();
10
11type Listener<Value> = (newValue: Value) => void;
12
13export function makeUIMutable<Value>(initial: Value): Mutable<Value> {
14 'worklet';
15
16 const listeners = new Map<number, Listener<Value>>();
17 let value = initial;
18
19 const self: Mutable<Value> = {
20 set value(newValue) {
21 valueSetter(self, newValue);
22 },
23 get value() {
24 return value;
25 },
26 /**
27 * _value prop should only be accessed by the valueSetter implementation
28 * which may make the decision about updating the mutable value depending
29 * on the provided new value. All other places should only attempt to modify
30 * the mutable by assigning to value prop directly.
31 */
32 set _value(newValue: Value) {
33 value = newValue;
34 listeners.forEach((listener) => {
35 listener(newValue);
36 });
37 },
38 get _value(): Value {
39 return value;
40 },
41 modify: (modifier, forceUpdate = true) => {
42 valueSetter(
43 self,
44 modifier !== undefined ? modifier(value) : value,
45 forceUpdate
46 );
47 },
48 addListener: (id: number, listener: Listener<Value>) => {
49 listeners.set(id, listener);
50 },
51 removeListener: (id: number) => {
52 listeners.delete(id);
53 },
54 _animation: null,
55 _isReanimatedSharedValue: true,
56 };
57 return self;
58}
59
60export function makeMutable<Value>(initial: Value): Mutable<Value> {
61 let value: Value = initial;
62 const handle = makeShareableCloneRecursive({
63 __init: () => {
64 'worklet';
65 return makeUIMutable(initial);
66 },
67 });
68 // listeners can only work on JS thread on Web and jest environments
69 const listeners = SHOULD_BE_USE_WEB
70 ? new Map<number, Listener<Value>>()
71 : undefined;
72 const mutable: Mutable<Value> = {
73 set value(newValue) {
74 if (SHOULD_BE_USE_WEB) {
75 valueSetter(mutable, newValue);
76 } else {
77 runOnUI(() => {
78 mutable.value = newValue;
79 })();
80 }
81 },
82 get value(): Value {
83 if (SHOULD_BE_USE_WEB) {
84 return value;
85 }
86 const uiValueGetter = executeOnUIRuntimeSync((sv: Mutable<Value>) => {
87 return sv.value;
88 });
89 return uiValueGetter(mutable);
90 },
91 set _value(newValue: Value) {
92 if (!SHOULD_BE_USE_WEB) {
93 throw new Error(
94 '[Reanimated] Setting `_value` directly is only possible on the UI runtime. Perhaps you want to assign to `value` instead?'
95 );
96 }
97 value = newValue;
98 listeners!.forEach((listener) => {
99 listener(newValue);
100 });
101 },
102 get _value(): Value {
103 if (SHOULD_BE_USE_WEB) {
104 return value;
105 }
106 throw new Error(
107 '[Reanimated] Reading from `_value` directly is only possible on the UI runtime. Perhaps you passed an Animated Style to a non-animated component?'
108 );
109 },
110
111 modify: (modifier, forceUpdate = true) => {
112 if (!SHOULD_BE_USE_WEB) {
113 runOnUI(() => {
114 mutable.modify(modifier, forceUpdate);
115 })();
116 } else {
117 valueSetter(
118 mutable,
119 modifier !== undefined ? modifier(mutable.value) : mutable.value,
120 forceUpdate
121 );
122 }
123 },
124 addListener: (id: number, listener: Listener<Value>) => {
125 if (!SHOULD_BE_USE_WEB) {
126 throw new Error(
127 '[Reanimated] Adding listeners is only possible on the UI runtime.'
128 );
129 }
130 listeners!.set(id, listener);
131 },
132 removeListener: (id: number) => {
133 if (!SHOULD_BE_USE_WEB) {
134 throw new Error(
135 '[Reanimated] Removing listeners is only possible on the UI runtime.'
136 );
137 }
138 listeners!.delete(id);
139 },
140 _isReanimatedSharedValue: true,
141 };
142 shareableMappingCache.set(mutable, handle);
143 return mutable;
144}