From c14a27f0fb7aaee2ab645870d8bc321c4564de03 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E4=BA=91=E6=B3=A5?= <1656081615@qq.com>
Date: Thu, 13 Jul 2023 09:26:07 +0800
Subject: [PATCH] fix(useReactive): cannot set a object with read-only and
non-configurable property (#2247)
* fix: throw error when set a read-only and non-configurable data property
* style: update
---
.../src/useReactive/__tests__/index.test.tsx | 30 +++++++++++++++++++
packages/hooks/src/useReactive/index.ts | 6 ++++
2 files changed, 36 insertions(+)
diff --git a/packages/hooks/src/useReactive/__tests__/index.test.tsx b/packages/hooks/src/useReactive/__tests__/index.test.tsx
index c261658709..954d3b71ec 100644
--- a/packages/hooks/src/useReactive/__tests__/index.test.tsx
+++ b/packages/hooks/src/useReactive/__tests__/index.test.tsx
@@ -195,6 +195,36 @@ describe('test useReactive feature', () => {
expect(() => result.current.v.Module).not.toThrowError();
});
+ it('test JSX element', () => {
+ const hook = renderHook(() => useReactive({ html:
foo
}));
+ const proxy = hook.result.current;
+ const wrap = render(proxy.html);
+ const html = wrap.getByRole('id');
+
+ expect(html.textContent).toBe('foo');
+ act(() => {
+ proxy.html = bar
;
+ wrap.rerender(proxy.html);
+ });
+ expect(html.textContent).toBe('bar');
+ hook.unmount();
+ });
+
+ it('test read-only and non-configurable data property', () => {
+ const obj = {} as { user: { name: string } };
+ Reflect.defineProperty(obj, 'user', {
+ value: { name: 'foo' },
+ writable: false,
+ configurable: false,
+ });
+
+ const hook = renderHook(() => useReactive(obj));
+ const proxy = hook.result.current;
+
+ expect(() => proxy.user.name).not.toThrowError();
+ hook.unmount();
+ });
+
it('test input1', () => {
const wrap = render();
diff --git a/packages/hooks/src/useReactive/index.ts b/packages/hooks/src/useReactive/index.ts
index 1543e9b3aa..ddeebd7045 100644
--- a/packages/hooks/src/useReactive/index.ts
+++ b/packages/hooks/src/useReactive/index.ts
@@ -26,6 +26,12 @@ function observer>(initialVal: T, cb: () => void):
get(target, key, receiver) {
const res = Reflect.get(target, key, receiver);
+ // https://github.com/alibaba/hooks/issues/1317
+ const descriptor = Reflect.getOwnPropertyDescriptor(target, key);
+ if (!descriptor?.configurable && !descriptor?.writable) {
+ return res;
+ }
+
// Only proxy plain object or array,
// otherwise it will cause: https://github.com/alibaba/hooks/issues/2080
return isPlainObject(res) || Array.isArray(res) ? observer(res, cb) : res;