react-native-hox 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +160 -133
- package/dist/index.d.mts +1 -2
- package/dist/index.d.ts +1 -2
- package/dist/index.js +12 -31
- package/dist/index.mjs +11 -31
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,168 +1,204 @@
|
|
|
1
1
|
# react-native-hox
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
> 极简、高性能、生产级特性开箱即用。
|
|
3
|
+
面向 React Native 的轻量状态管理方案:类型安全、API 极简,支持组件内 Hook 与组件外 Vanilla 读写,并内置可选持久化能力。
|
|
5
4
|
|
|
6
5
|
[](https://www.npmjs.com/package/react-native-hox)
|
|
7
6
|
[](https://www.typescriptlang.org/)
|
|
8
|
-
[](https://
|
|
7
|
+
[](https://www.npmjs.com/package/react-native-hox)
|
|
9
8
|
|
|
10
|
-
##
|
|
9
|
+
## 快速开始
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
### 安装
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
```bash
|
|
14
|
+
npm i react-native-hox
|
|
15
|
+
```
|
|
15
16
|
|
|
16
|
-
###
|
|
17
|
+
### 最小示例
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
* 🎯 **精准渲染**:支持 Selector 选择器,确保组件仅在关注的数据变化时更新。
|
|
22
|
-
* 🔌 **脱离组件运行**:完整的 Vanilla API,支持在 Axios 拦截器、事件回调等非组件环境读写状态。
|
|
19
|
+
```ts
|
|
20
|
+
// stores/user.ts
|
|
21
|
+
import { createModel } from 'react-native-hox';
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
export const userStore = createModel({ name: 'Guest' }); // 数据只存在内存
|
|
24
|
+
// export const userStore = createModel({ name: 'Guest' }, { persist: 'user_v1' }); // 数据存在缓存 AsyncStorage
|
|
25
|
+
```
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
```tsx
|
|
28
|
+
// Profile.tsx
|
|
29
|
+
import React from 'react';
|
|
30
|
+
import { View, Text, Button } from 'react-native';
|
|
31
|
+
import { userStore } from './stores/user';
|
|
27
32
|
|
|
28
|
-
|
|
33
|
+
export function Profile() {
|
|
34
|
+
const user = userStore.getState();
|
|
35
|
+
return (
|
|
36
|
+
<View>
|
|
37
|
+
<Text>Hello, {user.name}</Text>
|
|
38
|
+
<Button title="Set Name" onPress={() => userStore.setState({ name: 'Tom' })} />
|
|
39
|
+
</View>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
```
|
|
29
43
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
44
|
+
## 功能点
|
|
45
|
+
|
|
46
|
+
### 1) 更新状态:自动合并 / 显式替换
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import { createModel } from 'react-native-hox';
|
|
50
|
+
|
|
51
|
+
export const profileStore = createModel({ name: 'Guest', role: 'user' as 'user' | 'admin' });
|
|
34
52
|
```
|
|
35
53
|
|
|
36
|
-
|
|
54
|
+
```tsx
|
|
55
|
+
import React from 'react';
|
|
56
|
+
import { View, Text, Button } from 'react-native';
|
|
57
|
+
import { profileStore } from './stores/profile';
|
|
37
58
|
|
|
38
|
-
|
|
59
|
+
export function UpdateExample() {
|
|
60
|
+
const profile = profileStore.getState();
|
|
39
61
|
|
|
40
|
-
|
|
41
|
-
|
|
62
|
+
return (
|
|
63
|
+
<View>
|
|
64
|
+
<Text>{profile.name}</Text>
|
|
65
|
+
<Text>{profile.role}</Text>
|
|
66
|
+
<Button title="Merge Update" onPress={() => profileStore.setState({ name: 'Alice' })} />
|
|
67
|
+
<Button title="Replace" onPress={() => profileStore.setState({ name: 'Bob', role: 'admin' }, true)} />
|
|
68
|
+
</View>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 2) Selector:只在关注的数据变化时重渲染
|
|
74
|
+
|
|
75
|
+
```ts
|
|
42
76
|
import { createModel } from 'react-native-hox';
|
|
43
77
|
|
|
44
|
-
|
|
45
|
-
export const userStore = createModel({
|
|
46
|
-
name: 'Guest',
|
|
47
|
-
token: '',
|
|
48
|
-
isLogin: false,
|
|
49
|
-
}, {
|
|
50
|
-
persist: 'user_v1', // 开启持久化,数据自动存入 AsyncStorage/localStorage
|
|
51
|
-
});
|
|
78
|
+
export const counterStore = createModel({ count: 0, text: 'a' });
|
|
52
79
|
```
|
|
53
80
|
|
|
54
81
|
```tsx
|
|
55
|
-
|
|
56
|
-
import {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const name = userStore.getState(s => s.name);
|
|
62
|
-
|
|
63
|
-
const login = () => {
|
|
64
|
-
// 2. 更新状态:自动合并,无需 ...user
|
|
65
|
-
userStore.setState({
|
|
66
|
-
name: 'Admin',
|
|
67
|
-
isLogin: true
|
|
68
|
-
});
|
|
69
|
-
};
|
|
82
|
+
import React from 'react';
|
|
83
|
+
import { View, Text, Button } from 'react-native';
|
|
84
|
+
import { counterStore } from './stores/counter';
|
|
85
|
+
|
|
86
|
+
export function SelectorExample() {
|
|
87
|
+
const count = counterStore.getState((s) => s.count);
|
|
70
88
|
|
|
71
89
|
return (
|
|
72
90
|
<View>
|
|
73
|
-
<Text>
|
|
74
|
-
<Button onPress={
|
|
91
|
+
<Text>{count}</Text>
|
|
92
|
+
<Button title="Inc" onPress={() => counterStore.setState((s) => ({ count: s.count + 1 }))} />
|
|
93
|
+
<Button title="Change Text" onPress={() => counterStore.setState({ text: String(Math.random()) })} />
|
|
75
94
|
</View>
|
|
76
95
|
);
|
|
77
96
|
}
|
|
78
97
|
```
|
|
79
98
|
|
|
80
|
-
|
|
99
|
+
当 selector 返回对象/数组时,传入 `equalityFn`(例如 `shallow`)避免无意义重渲染:
|
|
81
100
|
|
|
82
101
|
```tsx
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
```
|
|
102
|
+
import { shallow } from 'react-native-hox';
|
|
103
|
+
import { counterStore } from './stores/counter';
|
|
104
|
+
|
|
105
|
+
const picked = counterStore.getState((s) => ({ count: s.count }), shallow);
|
|
106
|
+
```
|
|
89
107
|
|
|
90
|
-
|
|
108
|
+
### 3) 组件外读写:Vanilla API
|
|
91
109
|
|
|
92
|
-
|
|
110
|
+
```ts
|
|
111
|
+
import { userStore } from './stores/user';
|
|
93
112
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
**现在**:
|
|
113
|
+
const name1 = userStore.data.state.name;
|
|
114
|
+
const name2 = userStore.data.getState().name;
|
|
97
115
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
persist: 'app_theme' // ✅ Done. 自动防抖,自动恢复。
|
|
116
|
+
const unsub = userStore.data.subscribe((next, prev) => {
|
|
117
|
+
console.log(next, prev);
|
|
101
118
|
});
|
|
119
|
+
unsub();
|
|
102
120
|
```
|
|
103
121
|
|
|
104
|
-
###
|
|
105
|
-
**以前**:为了在 API 拦截器里拿 Token,不得不把 store 挂载到 window 或者引入复杂的 hack。
|
|
106
|
-
**现在**:
|
|
122
|
+
### 4) 持久化:persist(默认 AsyncStorage)
|
|
107
123
|
|
|
108
|
-
|
|
109
|
-
// api.ts
|
|
110
|
-
import { userStore } from './store/user';
|
|
124
|
+
只要提供一个 key 即可开启持久化(默认使用 `@react-native-async-storage/async-storage`,无需重复传 `storage`):
|
|
111
125
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
return config;
|
|
119
|
-
});
|
|
126
|
+
```ts
|
|
127
|
+
import { createModel } from 'react-native-hox';
|
|
128
|
+
|
|
129
|
+
export const authStore = createModel({ token: '' }, { persist: 'auth_v1' });
|
|
130
|
+
```
|
|
120
131
|
|
|
121
|
-
|
|
122
|
-
userStore.data.setState({ token: '' }); // 登出
|
|
123
|
-
```+ ### 3. API 统一性 (New)
|
|
124
|
-
+ **以前**:Redux `useSelector` vs `dispatch`,Context `useContext` vs `dispatch`。
|
|
125
|
-
+ **现在**:
|
|
126
|
-
+ * 读 (React):`userStore.getState()`
|
|
127
|
-
+ * 读 (Vanilla):`userStore.data.state`
|
|
128
|
-
+ * 写 (Universal):`userStore.setState()`
|
|
132
|
+
如果你希望替换存储引擎,可以在 `persist.storage` 传入实现同等接口的存储对象:
|
|
129
133
|
|
|
130
|
-
|
|
134
|
+
```ts
|
|
135
|
+
import { createModel } from 'react-native-hox';
|
|
136
|
+
import type { StorageEngine } from 'react-native-hox';
|
|
131
137
|
|
|
132
|
-
|
|
138
|
+
const storage: StorageEngine = {
|
|
139
|
+
getItem: async (key) => null,
|
|
140
|
+
setItem: async (key, value) => {},
|
|
141
|
+
removeItem: async (key) => {},
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
export const authStore = createModel({ token: '' }, { persist: { key: 'auth_v1', storage } });
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### 5) reset / destroy / strict
|
|
133
148
|
|
|
134
149
|
```ts
|
|
135
|
-
import
|
|
136
|
-
import { userStore } from './store/user';
|
|
137
|
-
|
|
138
|
-
axios.interceptors.request.use((config) => {
|
|
139
|
-
const token = userStore.data.state.token;
|
|
140
|
-
if (token) {
|
|
141
|
-
config.headers = config.headers ?? {};
|
|
142
|
-
config.headers.Authorization = `Bearer ${token}`;
|
|
143
|
-
}
|
|
144
|
-
return config;
|
|
145
|
-
});
|
|
150
|
+
import { userStore } from './stores/user';
|
|
146
151
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
152
|
+
userStore.reset();
|
|
153
|
+
userStore.destroy();
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
import { createModel } from 'react-native-hox';
|
|
158
|
+
|
|
159
|
+
export const strictStore = createModel(
|
|
160
|
+
{ count: 0 },
|
|
161
|
+
{ strict: { forbidSetStateAfterDestroy: true } }
|
|
155
162
|
);
|
|
156
163
|
```
|
|
157
164
|
|
|
158
|
-
|
|
165
|
+
## 进阶使用
|
|
159
166
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
167
|
+
### 1) subscribe(selector):只在 slice 变化时触发
|
|
168
|
+
|
|
169
|
+
```tsx
|
|
170
|
+
import React, { useEffect } from 'react';
|
|
171
|
+
import { View, Text } from 'react-native';
|
|
172
|
+
import { userStore } from './stores/user';
|
|
173
|
+
|
|
174
|
+
export function SubscribeExample() {
|
|
175
|
+
const name = userStore.getState((s) => s.name);
|
|
176
|
+
|
|
177
|
+
useEffect(() => {
|
|
178
|
+
const unsub = userStore.data.subscribe(
|
|
179
|
+
(s) => s.name,
|
|
180
|
+
(next, prev) => {
|
|
181
|
+
console.log('name changed:', prev, '->', next);
|
|
182
|
+
},
|
|
183
|
+
{ fireImmediately: true }
|
|
184
|
+
);
|
|
185
|
+
return unsub;
|
|
186
|
+
}, []);
|
|
187
|
+
|
|
188
|
+
return (
|
|
189
|
+
<View>
|
|
190
|
+
<Text>{name}</Text>
|
|
191
|
+
</View>
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### 2) 持久化安全边界:版本化与数据迁移
|
|
163
197
|
|
|
164
198
|
```ts
|
|
165
|
-
|
|
199
|
+
import { createModel } from 'react-native-hox';
|
|
200
|
+
|
|
201
|
+
export const userPersistStore = createModel(
|
|
166
202
|
{ token: '', isLogin: false },
|
|
167
203
|
{
|
|
168
204
|
persist: {
|
|
@@ -176,37 +212,28 @@ export const userStore = createModel(
|
|
|
176
212
|
);
|
|
177
213
|
```
|
|
178
214
|
|
|
179
|
-
### 3)
|
|
215
|
+
### 3) initialState 支持纯函数
|
|
180
216
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
```tsx
|
|
185
|
-
import { shallow } from 'react-native-hox';
|
|
217
|
+
```ts
|
|
218
|
+
import { createModel } from 'react-native-hox';
|
|
186
219
|
|
|
187
|
-
const
|
|
220
|
+
export const appStore = createModel(() => ({ bootAt: Date.now() }));
|
|
188
221
|
```
|
|
189
222
|
|
|
190
|
-
## API
|
|
223
|
+
## API 参考(简版)
|
|
191
224
|
|
|
192
225
|
### `createModel(initialState, options?)`
|
|
193
226
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
* `persist`: `string` (可选) - 持久化存储的唯一 Key。
|
|
227
|
+
- `initialState`: `T` 或 `() => T`
|
|
228
|
+
- `options.persist`: `string` 或 `{ key, storage?, debounce?, beforePersist?, beforeRecover? }`
|
|
229
|
+
- `options.strict.forbidSetStateAfterDestroy`: `boolean`
|
|
230
|
+
- `options.logger`: `{ warn, error }`
|
|
199
231
|
|
|
200
|
-
|
|
201
|
-
* `getState(selector?, equalityFn?)`: React Hook,在组件中读取状态。
|
|
202
|
-
* `useState(selector?, equalityFn?)`: `getState` 的别名。
|
|
203
|
-
* `use(selector?, equalityFn?)`: `getState` 的别名。
|
|
204
|
-
* `setState(patch)`: 更新状态。
|
|
205
|
-
* `reset()`: 重置为初始状态。
|
|
206
|
-
* `data`: 组件外 API,包含 `state` (getter), `getState` (fn), `setState`, `subscribe`, `reset`, `destroy`。
|
|
232
|
+
返回的 `Model` 同时支持:
|
|
207
233
|
|
|
208
|
-
|
|
234
|
+
- 组件内(Hook):`model.getState()` / `model.use()` / `model.useState()`
|
|
235
|
+
- 组件外(Vanilla):`model.data.state` / `model.data.getState()` / `model.data.setState()` / `model.data.subscribe()`
|
|
209
236
|
|
|
210
237
|
## License
|
|
211
238
|
|
|
212
|
-
|
|
239
|
+
ISC
|
package/dist/index.d.mts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
+
type Listener<T> = (state: T, prevState: T) => void;
|
|
1
2
|
interface StorageEngine {
|
|
2
3
|
getItem: (key: string) => string | null | Promise<string | null>;
|
|
3
4
|
setItem: (key: string, value: string) => void | Promise<void>;
|
|
4
5
|
removeItem: (key: string) => void | Promise<void>;
|
|
5
6
|
}
|
|
6
|
-
|
|
7
|
-
type Listener<T> = (state: T, prevState: T) => void;
|
|
8
7
|
type EqualityFn<T> = (a: T, b: T) => boolean;
|
|
9
8
|
|
|
10
9
|
type Selector<T, U> = (state: T) => U;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
+
type Listener<T> = (state: T, prevState: T) => void;
|
|
1
2
|
interface StorageEngine {
|
|
2
3
|
getItem: (key: string) => string | null | Promise<string | null>;
|
|
3
4
|
setItem: (key: string, value: string) => void | Promise<void>;
|
|
4
5
|
removeItem: (key: string) => void | Promise<void>;
|
|
5
6
|
}
|
|
6
|
-
|
|
7
|
-
type Listener<T> = (state: T, prevState: T) => void;
|
|
8
7
|
type EqualityFn<T> = (a: T, b: T) => boolean;
|
|
9
8
|
|
|
10
9
|
type Selector<T, U> = (state: T) => U;
|
package/dist/index.js
CHANGED
|
@@ -1,43 +1,23 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var useSyncExternalStoreExports = require('use-sync-external-store/shim/with-selector');
|
|
4
|
+
var AsyncStorage = require('@react-native-async-storage/async-storage');
|
|
4
5
|
|
|
5
6
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
6
7
|
|
|
7
8
|
var useSyncExternalStoreExports__default = /*#__PURE__*/_interopDefault(useSyncExternalStoreExports);
|
|
9
|
+
var AsyncStorage__default = /*#__PURE__*/_interopDefault(AsyncStorage);
|
|
8
10
|
|
|
9
11
|
// src/createModel.ts
|
|
10
12
|
|
|
11
|
-
// src/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if (hasCachedDefaultWebStorage) {
|
|
16
|
-
return cachedDefaultWebStorage;
|
|
17
|
-
}
|
|
18
|
-
hasCachedDefaultWebStorage = true;
|
|
19
|
-
try {
|
|
20
|
-
const anyGlobal = globalThis;
|
|
21
|
-
const storage = anyGlobal == null ? void 0 : anyGlobal.localStorage;
|
|
22
|
-
if (!storage) {
|
|
23
|
-
return void 0;
|
|
24
|
-
}
|
|
25
|
-
const testKey = "__react_native_hox_test__";
|
|
26
|
-
storage.setItem(testKey, "1");
|
|
27
|
-
storage.removeItem(testKey);
|
|
28
|
-
cachedDefaultWebStorage = {
|
|
29
|
-
getItem: (key) => storage.getItem(key),
|
|
30
|
-
setItem: (key, value) => storage.setItem(key, value),
|
|
31
|
-
removeItem: (key) => storage.removeItem(key)
|
|
32
|
-
};
|
|
33
|
-
return cachedDefaultWebStorage;
|
|
34
|
-
} catch {
|
|
35
|
-
cachedDefaultWebStorage = void 0;
|
|
36
|
-
return void 0;
|
|
13
|
+
// src/vanilla.ts
|
|
14
|
+
function isPlainObject(value) {
|
|
15
|
+
if (Object.prototype.toString.call(value) !== "[object Object]") {
|
|
16
|
+
return false;
|
|
37
17
|
}
|
|
18
|
+
const proto = Object.getPrototypeOf(value);
|
|
19
|
+
return proto === Object.prototype || proto === null;
|
|
38
20
|
}
|
|
39
|
-
|
|
40
|
-
// src/vanilla.ts
|
|
41
21
|
var createStore = (initialState) => {
|
|
42
22
|
let state = initialState;
|
|
43
23
|
const listeners = /* @__PURE__ */ new Set();
|
|
@@ -45,7 +25,8 @@ var createStore = (initialState) => {
|
|
|
45
25
|
const nextState = typeof partial === "function" ? partial(state) : partial;
|
|
46
26
|
if (!Object.is(nextState, state)) {
|
|
47
27
|
const previousState = state;
|
|
48
|
-
|
|
28
|
+
const shouldReplace = replace != null ? replace : !isPlainObject(state) || !isPlainObject(nextState);
|
|
29
|
+
state = shouldReplace ? nextState : Object.assign({}, state, nextState);
|
|
49
30
|
listeners.forEach((listener) => listener(state, previousState));
|
|
50
31
|
}
|
|
51
32
|
};
|
|
@@ -216,7 +197,7 @@ function setupModelSideEffects(store, options, logger) {
|
|
|
216
197
|
var _a, _b, _c, _d;
|
|
217
198
|
const persist = typeof (options == null ? void 0 : options.persist) === "string" ? { key: options.persist } : options == null ? void 0 : options.persist;
|
|
218
199
|
const persistKey = persist == null ? void 0 : persist.key;
|
|
219
|
-
const storage = (_a = persist == null ? void 0 : persist.storage) != null ? _a :
|
|
200
|
+
const storage = (_a = persist == null ? void 0 : persist.storage) != null ? _a : AsyncStorage__default.default;
|
|
220
201
|
if (!persistKey) {
|
|
221
202
|
return;
|
|
222
203
|
}
|
|
@@ -225,7 +206,7 @@ function setupModelSideEffects(store, options, logger) {
|
|
|
225
206
|
const debounceMs = (_d = persist == null ? void 0 : persist.debounce) != null ? _d : 100;
|
|
226
207
|
if (!storage) {
|
|
227
208
|
logger.warn(
|
|
228
|
-
"[react-native-hox] persist \u5DF2\u5F00\u542F\u4F46 storage \u4E0D\u53EF\u7528\
|
|
209
|
+
"[react-native-hox] persist \u5DF2\u5F00\u542F\u4F46 storage \u4E0D\u53EF\u7528\uFF1A\u8BF7\u5728 persist.storage \u4F20\u5165 AsyncStorage/MMKV \u7B49\u3002"
|
|
229
210
|
);
|
|
230
211
|
return;
|
|
231
212
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -1,37 +1,16 @@
|
|
|
1
1
|
import useSyncExternalStoreExports from 'use-sync-external-store/shim/with-selector';
|
|
2
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
2
3
|
|
|
3
4
|
// src/createModel.ts
|
|
4
5
|
|
|
5
|
-
// src/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if (hasCachedDefaultWebStorage) {
|
|
10
|
-
return cachedDefaultWebStorage;
|
|
11
|
-
}
|
|
12
|
-
hasCachedDefaultWebStorage = true;
|
|
13
|
-
try {
|
|
14
|
-
const anyGlobal = globalThis;
|
|
15
|
-
const storage = anyGlobal == null ? void 0 : anyGlobal.localStorage;
|
|
16
|
-
if (!storage) {
|
|
17
|
-
return void 0;
|
|
18
|
-
}
|
|
19
|
-
const testKey = "__react_native_hox_test__";
|
|
20
|
-
storage.setItem(testKey, "1");
|
|
21
|
-
storage.removeItem(testKey);
|
|
22
|
-
cachedDefaultWebStorage = {
|
|
23
|
-
getItem: (key) => storage.getItem(key),
|
|
24
|
-
setItem: (key, value) => storage.setItem(key, value),
|
|
25
|
-
removeItem: (key) => storage.removeItem(key)
|
|
26
|
-
};
|
|
27
|
-
return cachedDefaultWebStorage;
|
|
28
|
-
} catch {
|
|
29
|
-
cachedDefaultWebStorage = void 0;
|
|
30
|
-
return void 0;
|
|
6
|
+
// src/vanilla.ts
|
|
7
|
+
function isPlainObject(value) {
|
|
8
|
+
if (Object.prototype.toString.call(value) !== "[object Object]") {
|
|
9
|
+
return false;
|
|
31
10
|
}
|
|
11
|
+
const proto = Object.getPrototypeOf(value);
|
|
12
|
+
return proto === Object.prototype || proto === null;
|
|
32
13
|
}
|
|
33
|
-
|
|
34
|
-
// src/vanilla.ts
|
|
35
14
|
var createStore = (initialState) => {
|
|
36
15
|
let state = initialState;
|
|
37
16
|
const listeners = /* @__PURE__ */ new Set();
|
|
@@ -39,7 +18,8 @@ var createStore = (initialState) => {
|
|
|
39
18
|
const nextState = typeof partial === "function" ? partial(state) : partial;
|
|
40
19
|
if (!Object.is(nextState, state)) {
|
|
41
20
|
const previousState = state;
|
|
42
|
-
|
|
21
|
+
const shouldReplace = replace != null ? replace : !isPlainObject(state) || !isPlainObject(nextState);
|
|
22
|
+
state = shouldReplace ? nextState : Object.assign({}, state, nextState);
|
|
43
23
|
listeners.forEach((listener) => listener(state, previousState));
|
|
44
24
|
}
|
|
45
25
|
};
|
|
@@ -210,7 +190,7 @@ function setupModelSideEffects(store, options, logger) {
|
|
|
210
190
|
var _a, _b, _c, _d;
|
|
211
191
|
const persist = typeof (options == null ? void 0 : options.persist) === "string" ? { key: options.persist } : options == null ? void 0 : options.persist;
|
|
212
192
|
const persistKey = persist == null ? void 0 : persist.key;
|
|
213
|
-
const storage = (_a = persist == null ? void 0 : persist.storage) != null ? _a :
|
|
193
|
+
const storage = (_a = persist == null ? void 0 : persist.storage) != null ? _a : AsyncStorage;
|
|
214
194
|
if (!persistKey) {
|
|
215
195
|
return;
|
|
216
196
|
}
|
|
@@ -219,7 +199,7 @@ function setupModelSideEffects(store, options, logger) {
|
|
|
219
199
|
const debounceMs = (_d = persist == null ? void 0 : persist.debounce) != null ? _d : 100;
|
|
220
200
|
if (!storage) {
|
|
221
201
|
logger.warn(
|
|
222
|
-
"[react-native-hox] persist \u5DF2\u5F00\u542F\u4F46 storage \u4E0D\u53EF\u7528\
|
|
202
|
+
"[react-native-hox] persist \u5DF2\u5F00\u542F\u4F46 storage \u4E0D\u53EF\u7528\uFF1A\u8BF7\u5728 persist.storage \u4F20\u5165 AsyncStorage/MMKV \u7B49\u3002"
|
|
223
203
|
);
|
|
224
204
|
return;
|
|
225
205
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-hox",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "一个轻量级、类型安全、零心智负担的 React Native 状态管理解决方案。",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-native",
|
|
@@ -45,11 +45,12 @@
|
|
|
45
45
|
"prepack": "npm run build"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
+
"@react-native-async-storage/async-storage": "^2.2.0",
|
|
48
49
|
"use-sync-external-store": "^1.6.0"
|
|
49
50
|
},
|
|
50
51
|
"peerDependencies": {
|
|
51
52
|
"react": ">=16.8",
|
|
52
|
-
"react-native": ">=0.
|
|
53
|
+
"react-native": ">=0.65"
|
|
53
54
|
},
|
|
54
55
|
"devDependencies": {
|
|
55
56
|
"@types/jest": "^30.0.0",
|