Skip to content

Commit

Permalink
feat!: remove useDefined hook
Browse files Browse the repository at this point in the history
  • Loading branch information
geekact committed Sep 8, 2023
1 parent fdabe53 commit 2296a83
Show file tree
Hide file tree
Showing 11 changed files with 18 additions and 440 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## v3

- 删除hooks `useDefined`

## [2.0.1](https://github.com/foca-js/foca/compare/v2.0.0...v2.0.1)  (2023-08-10)

- react-redux 版本从 8.1.1 升级到 8.1.2 (#40)
Expand Down
37 changes: 0 additions & 37 deletions docs/advanced.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,43 +37,6 @@ const user3Model = cloneModel('users3', userModel, (prev) => {
});
```

# 局部模型

通过`defineModel``cloneModel`创建的模型均为全局类别的模型,数据一直保持在内存中,直到应用关闭或者退出才会释放,对于比较大的项目,这可能会有性能问题。所以有时候你其实想要一种`用完就扔`的模型,即在 React 组件初始化时把模型数据扔到 store 中,当 React 组件被销毁时,模型的数据也跟着销毁。现在局部模型很适合你的需求:

```tsx
import { useEffect } from 'react';
import { defineModel, useDefined } from 'foca';

// test.model.ts
export const testModel = defineModel('test', {
initialState: { count: 0 },
reducers: {
plus(state, value: number) {
state.count += value;
},
},
});

// App.tsx
const App: FC = () => {
const model = useDefined(testModel);
const { count } = useModel(model);

useEffect(() => {
model.plus(1);
}, []);

return <div>{count}</div>;
};
```

利用 `useDefined` 函数根据全局模型创建一个新的局部模型,然后就是通用的模型操作,这似乎没有增加工作量(因为只多了一行)。下面我列举了局部函数的几个特点:

- 组件内部使用,不污染全局
- 数据随组件自动挂载/释放
- 有效降低内存占用量

# loadings

默认地,methods 函数只会保存一份执行状态,如果你在同一时间多次执行同一个函数,那么状态就会互相覆盖,产生错乱的数据。如果现在有 10 个按钮,点击每个按钮都会执行`model.methodX(id)`,那么我们如何知道是哪个按钮执行的呢?这时候我们需要为执行状态开辟一个独立的存储空间,让同一个函数拥有多个状态互不干扰。
Expand Down
23 changes: 11 additions & 12 deletions docs/api.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
| 方法 | 描述 | 使用频率 | 指南 |
| ----------------- | --------------------------------------- | ----------------------------------- | ------------------------------------- |
| **store.init** | 初始化仓库 | :star2: | [开始使用](/initialize?id=仓库) |
| **store.refresh** | 重置仓库数据 | :star2: | [进阶用法](/advanced?id=重置所有数据) |
| **defineModel** | 创建模型 | :star2::star2::star2::star2::star2: | [模型](/model?id=model) |
| **cloneModel** | 复制模型并允许小量修改 | :star2: | [进阶用法](/advanced?id=克隆模型) |
| **useDefined** | 在 hooks 中创建局部模型,数据随组件释放 | :star2::star2::star2: | [进阶用法](/advanced?id=局部模型) |
| **useModel** | 在 hooks 中使用模型的状态 | :star2::star2::star2::star2::star2: | [数据对接](/react?id=usemodel) |
| **useComputed** | 在 hooks 中使用计算属性 | :star2::star2::star2: | [数据对接](/react?id=usecomputed) |
| **useLoading** | 在 hooks 中获取异步函数的执行状态 | :star2::star2::star2::star2::star2: | [数据对接](/react?id=useloading) |
| **getLoading** | 获取异步函数的当前执行状态 | :star2: | [通用属性](/model?id=loading) |
| **connect** | 在 class 组件中连接 react 和 redux | :star2: | [数据对接](/react?id=connect) |
| 方法 | 描述 | 使用频率 | 指南 |
| ----------------- | ---------------------------------- | ----------------------------------- | ------------------------------------- |
| **store.init** | 初始化仓库 | :star2: | [开始使用](/initialize?id=仓库) |
| **store.refresh** | 重置仓库数据 | :star2: | [进阶用法](/advanced?id=重置所有数据) |
| **defineModel** | 创建模型 | :star2::star2::star2::star2::star2: | [模型](/model?id=model) |
| **cloneModel** | 复制模型并允许小量修改 | :star2: | [进阶用法](/advanced?id=克隆模型) |
| **useModel** | 在 hooks 中使用模型的状态 | :star2::star2::star2::star2::star2: | [数据对接](/react?id=usemodel) |
| **useComputed** | 在 hooks 中使用计算属性 | :star2::star2::star2: | [数据对接](/react?id=usecomputed) |
| **useLoading** | 在 hooks 中获取异步函数的执行状态 | :star2::star2::star2::star2::star2: | [数据对接](/react?id=useloading) |
| **getLoading** | 获取异步函数的当前执行状态 | :star2: | [通用属性](/model?id=loading) |
| **connect** | 在 class 组件中连接 react 和 redux | :star2: | [数据对接](/react?id=connect) |
21 changes: 0 additions & 21 deletions docs/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,24 +63,3 @@ export const testModel = defineModel('test', {
},
});
```

## onDestroy

模型数据从 store 卸载时的回调通知。onDestroy 事件只针对`局部模型`,即通过`useDefined`这个 hooks api 创建的模型才会触发,因为局部模型是跟随组件一起创建和销毁的。

注意,当触发 onDestroy 回调时,模型已经被卸载了,所以无法再拿到当前数据,而且`this`上下文也被限制使用了。

```typescript
import { defineModel } from 'foca';

const initialState = { count: 0 };

export const testModel = defineModel('test', {
initialState,
events: {
onDestroy() {
console.log('Destroyed');
},
},
});
```
4 changes: 2 additions & 2 deletions docs/mindMap.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ export { useLoading } from './api/useLoading';
export { getLoading } from './api/getLoading';
export { connect } from './redux/connect';
export { useComputed } from './reactive/useComputed';
export { useDefined } from './model/useDefined';

// 入口使用
export { compose } from 'redux';
Expand Down
15 changes: 1 addition & 14 deletions src/model/defineModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ export const defineModel = <
}

if (events) {
const { onInit, onChange, onDestroy } = events;
const { onInit, onChange } = events;
const eventCtx: EventCtx<State> = Object.assign(
composeGetter({ name: uniqueName }, getState),
enhancedMethods.external,
Expand All @@ -233,19 +233,6 @@ export const defineModel = <
);
}

if (onDestroy) {
subscriptions.push(
modelStore.subscribe(() => {
if (eventCtx.state === void 0) {
for (let i = 0; i < subscriptions.length; ++i) {
subscriptions[i]!();
}
onDestroy.call(null as never);
}
}),
);
}

if (onInit) {
/**
* 初始化时,用到它的React组件可能还没加载,所以执行async-method时无法判断是否需要保存loading。因此需要一个钩子来处理事件周期
Expand Down
111 changes: 0 additions & 111 deletions src/model/useDefined.ts

This file was deleted.

61 changes: 0 additions & 61 deletions test/lifecycle.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import sleep from 'sleep-promise';
import { cloneModel, defineModel, engines, store } from '../src';
import { PersistSchema } from '../src/persist/PersistItem';
import { ModelStore } from '../src/store/modelStore';

describe('onInit', () => {
afterEach(() => {
Expand Down Expand Up @@ -188,63 +187,3 @@ describe('onChange', () => {
);
});
});

describe('onDestroy', () => {
beforeEach(() => {
store.init();
});

afterEach(() => {
store.unmount();
});

test('call onDestroy when invoke store.destroy()', async () => {
const spy = vitest.fn();
const model = defineModel('events' + Math.random(), {
initialState: { count: 0 },
reducers: {
update(state) {
state.count += 1;
},
},
events: {
onDestroy: spy,
},
});

await store.onInitialized();

model.update();
expect(spy).toBeCalledTimes(0);
ModelStore.removeReducer.call(store, model.name);
expect(spy).toBeCalledTimes(1);
spy.mockRestore();
});

test('should not call onChange', async () => {
const destroySpy = vitest.fn();
const changeSpy = vitest.fn();
const model = defineModel('events' + Math.random(), {
initialState: { count: 0 },
reducers: {
update(state) {
state.count += 1;
},
},
events: {
onChange: changeSpy,
onDestroy: destroySpy,
},
});

await store.onInitialized();

model.update();
expect(destroySpy).toBeCalledTimes(0);
expect(changeSpy).toBeCalledTimes(1);
ModelStore.removeReducer.call(store, model.name);
expect(destroySpy).toBeCalledTimes(1);
expect(changeSpy).toBeCalledTimes(1);
destroySpy.mockRestore();
});
});
31 changes: 0 additions & 31 deletions test/typescript/useDefined.check.ts

This file was deleted.

Loading

0 comments on commit 2296a83

Please sign in to comment.