UNPKG

5.99 kBJavaScriptView Raw
1'use strict';
2
3import { shouldBeUseWeb } from "./PlatformChecker.js";
4import { ReanimatedError } from "./errors.js";
5import { logger } from "./logger/index.js";
6import { isFirstReactRender, isReactRendering } from "./reactUtils.js";
7import { shareableMappingCache } from "./shareableMappingCache.js";
8import { makeShareableCloneRecursive } from "./shareables.js";
9import { executeOnUIRuntimeSync, runOnUI } from "./threads.js";
10import { valueSetter } from "./valueSetter.js";
11const SHOULD_BE_USE_WEB = shouldBeUseWeb();
12function shouldWarnAboutAccessDuringRender() {
13 return __DEV__ && isReactRendering() && !isFirstReactRender();
14}
15function checkInvalidReadDuringRender() {
16 if (shouldWarnAboutAccessDuringRender()) {
17 logger.warn('Reading from `value` during component render. Please ensure that you do not access the `value` property or use `get` method of a shared value while React is rendering a component.', {
18 strict: true
19 });
20 }
21}
22function checkInvalidWriteDuringRender() {
23 if (shouldWarnAboutAccessDuringRender()) {
24 logger.warn('Writing to `value` during component render. Please ensure that you do not access the `value` property or use `set` method of a shared value while React is rendering a component.', {
25 strict: true
26 });
27 }
28}
29/**
30 * Adds `get` and `set` methods to the mutable object to handle access to
31 * `value` property.
32 *
33 * React Compiler disallows modifying return values of hooks. Even though
34 * assignment to `value` is a setter invocation, Compiler's static analysis
35 * doesn't detect it. That's why we provide a second API for users using the
36 * Compiler.
37 */
38function addCompilerSafeGetAndSet(mutable) {
39 'worklet';
40
41 Object.defineProperties(mutable, {
42 get: {
43 value() {
44 return mutable.value;
45 },
46 configurable: false,
47 enumerable: false
48 },
49 set: {
50 value(newValue) {
51 if (typeof newValue === 'function') {
52 mutable.value = newValue(mutable.value);
53 } else {
54 mutable.value = newValue;
55 }
56 },
57 configurable: false,
58 enumerable: false
59 }
60 });
61}
62/**
63 * Hides the internal `_value` property of a mutable. It won't be visible to:
64 *
65 * - `Object.keys`,
66 * - `const prop in obj`,
67 * - Etc.
68 *
69 * This way when the user accidentally sends the SharedValue to React, he won't
70 * get an obscure error message.
71 *
72 * We hide for both _React runtime_ and _Worklet runtime_ mutables for
73 * uniformity of behavior.
74 */
75function hideInternalValueProp(mutable) {
76 'worklet';
77
78 Object.defineProperty(mutable, '_value', {
79 configurable: false,
80 enumerable: false
81 });
82}
83export function makeMutableUI(initial) {
84 'worklet';
85
86 const listeners = new Map();
87 let value = initial;
88 const mutable = {
89 get value() {
90 return value;
91 },
92 set value(newValue) {
93 valueSetter(mutable, newValue);
94 },
95 get _value() {
96 return value;
97 },
98 set _value(newValue) {
99 value = newValue;
100 listeners.forEach(listener => {
101 listener(newValue);
102 });
103 },
104 modify: (modifier, forceUpdate = true) => {
105 valueSetter(mutable, modifier !== undefined ? modifier(value) : value, forceUpdate);
106 },
107 addListener: (id, listener) => {
108 listeners.set(id, listener);
109 },
110 removeListener: id => {
111 listeners.delete(id);
112 },
113 _animation: null,
114 _isReanimatedSharedValue: true
115 };
116 hideInternalValueProp(mutable);
117 addCompilerSafeGetAndSet(mutable);
118 return mutable;
119}
120function makeMutableNative(initial) {
121 const handle = makeShareableCloneRecursive({
122 __init: () => {
123 'worklet';
124
125 return makeMutableUI(initial);
126 }
127 });
128 const mutable = {
129 get value() {
130 checkInvalidReadDuringRender();
131 const uiValueGetter = executeOnUIRuntimeSync(sv => {
132 return sv.value;
133 });
134 return uiValueGetter(mutable);
135 },
136 set value(newValue) {
137 checkInvalidWriteDuringRender();
138 runOnUI(() => {
139 mutable.value = newValue;
140 })();
141 },
142 get _value() {
143 throw new ReanimatedError('Reading from `_value` directly is only possible on the UI runtime. Perhaps you passed an Animated Style to a non-animated component?');
144 },
145 set _value(_newValue) {
146 throw new ReanimatedError('Setting `_value` directly is only possible on the UI runtime. Perhaps you want to assign to `value` instead?');
147 },
148 modify: (modifier, forceUpdate = true) => {
149 runOnUI(() => {
150 mutable.modify(modifier, forceUpdate);
151 })();
152 },
153 addListener: () => {
154 throw new ReanimatedError('Adding listeners is only possible on the UI runtime.');
155 },
156 removeListener: () => {
157 throw new ReanimatedError('Removing listeners is only possible on the UI runtime.');
158 },
159 _isReanimatedSharedValue: true
160 };
161 hideInternalValueProp(mutable);
162 addCompilerSafeGetAndSet(mutable);
163 shareableMappingCache.set(mutable, handle);
164 return mutable;
165}
166function makeMutableWeb(initial) {
167 let value = initial;
168 const listeners = new Map();
169 const mutable = {
170 get value() {
171 checkInvalidReadDuringRender();
172 return value;
173 },
174 set value(newValue) {
175 checkInvalidWriteDuringRender();
176 valueSetter(mutable, newValue);
177 },
178 get _value() {
179 return value;
180 },
181 set _value(newValue) {
182 value = newValue;
183 listeners.forEach(listener => {
184 listener(newValue);
185 });
186 },
187 modify: (modifier, forceUpdate = true) => {
188 valueSetter(mutable, modifier !== undefined ? modifier(mutable.value) : mutable.value, forceUpdate);
189 },
190 addListener: (id, listener) => {
191 listeners.set(id, listener);
192 },
193 removeListener: id => {
194 listeners.delete(id);
195 },
196 _isReanimatedSharedValue: true
197 };
198 hideInternalValueProp(mutable);
199 addCompilerSafeGetAndSet(mutable);
200 return mutable;
201}
202export const makeMutable = SHOULD_BE_USE_WEB ? makeMutableWeb : makeMutableNative;
203//# sourceMappingURL=mutables.js.map
\No newline at end of file