Skip to content

Commit db5f4eb

Browse files
committed
fix(react-native): restore native proxy expandos
1 parent ce189b6 commit db5f4eb

3 files changed

Lines changed: 35 additions & 27 deletions

File tree

NativeScript/ffi/shared/jsi/NativeApiJsiHostObjects.h

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -977,20 +977,7 @@ class NativeApiObjectHostObject final
977977
return;
978978
}
979979

980-
if (property == "__nativeApiClassWrapper" ||
981-
isNativeApiJsiExtendedClass(object_getClass(object_))) {
982-
bridge_->setObjectExpando(runtime, object_, property, value);
983-
return;
984-
}
985-
986-
const char* className = object_getClassName(object_);
987-
throw facebook::jsi::JSError(
988-
runtime,
989-
"Cannot assign JavaScript property '" + property +
990-
"' to native proxy " +
991-
(className != nullptr ? std::string(className) : std::string("")) +
992-
". Native proxies only accept writable native properties; keep "
993-
"JavaScript state in a WeakMap or external object.");
980+
bridge_->setObjectExpando(runtime, object_, property, value);
994981
}
995982

996983
std::vector<PropNameID> getPropertyNames(Runtime& runtime) override {

packages/react-native/README.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -176,19 +176,20 @@ Context helpers cover common native view-manager patterns:
176176

177177
### State, delegates, and retention
178178

179-
Do not attach arbitrary JavaScript properties to native proxies. Native proxies
180-
now reject unsupported/custom assignments with a guidance error. Keep JS state in
181-
`WeakMap`, React state, or another external object:
179+
Native proxies support JavaScript expando properties for local state. Native
180+
property setters still win first, and unsupported names fall back to JS state:
182181

183182
```ts
184-
const state = new WeakMap<UIView, {selected: boolean}>();
185-
186183
NativeScript.runOnUI(() => {
187184
const view = UIView.new();
188-
state.set(view, {selected: false});
185+
view.ownerState = {selected: false};
186+
view.tag = 42; // still calls UIKit's native tag setter
189187
});
190188
```
191189

190+
Use `WeakMap`, React state, or another external object when you want state that
191+
is not tied to the lifetime of a specific native proxy.
192+
192193
UIKit often retains delegates and actions weakly or outlives the JavaScript
193194
closure that created them. Retain those helper objects explicitly. Use
194195
`ctx.retain()` inside `defineUIKitView()`, or a standalone retainer elsewhere:

test/react-native/ffi-compat/App.tsx

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1273,16 +1273,36 @@ function buildReactNativeIntegrationTests(): TestCase[] {
12731273
},
12741274
},
12751275
{
1276-
name: 'rejects arbitrary JavaScript state on native proxies with guidance',
1276+
name: 'preserves arbitrary JavaScript state on native proxies',
12771277
async run() {
12781278
await NativeScript.runOnUI(() => {
12791279
const view = g('UIView').new();
1280-
assertThrows(
1281-
() => {
1282-
view.__nativeScriptCustomState = {unsafe: true};
1283-
},
1284-
/WeakMap|native proxy/,
1285-
'custom native proxy property assignment',
1280+
const state = {selected: true, count: 1};
1281+
view.__nativeScriptCustomState = state;
1282+
assert(
1283+
view.__nativeScriptCustomState === state,
1284+
'custom native proxy state identity',
1285+
);
1286+
view.__nativeScriptCustomState.count++;
1287+
assertEqual(
1288+
state.count,
1289+
2,
1290+
'custom native proxy state remains mutable',
1291+
);
1292+
1293+
view.__nativeScriptCustomFlag = 'ok';
1294+
assertEqual(
1295+
view.__nativeScriptCustomFlag,
1296+
'ok',
1297+
'custom native proxy string state',
1298+
);
1299+
1300+
view.tag = 42;
1301+
assertEqual(view.tag, 42, 'native property setter still wins');
1302+
assertEqual(
1303+
view.__nativeScriptCustomFlag,
1304+
'ok',
1305+
'custom native proxy state survives native property writes',
12861306
);
12871307
});
12881308
},

0 commit comments

Comments
 (0)