Skip to content

Commit 464207d

Browse files
committed
增加测试用例-获取子组件服务
1 parent 5ea7a81 commit 464207d

File tree

8 files changed

+159
-1
lines changed

8 files changed

+159
-1
lines changed

src/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
Plugin,
1111
App,
1212
} from 'vue';
13+
export { findService } from './utils';
1314

1415
export const POST_REACTIVE = 'METADATA_KEY_POST_REACTIVE';
1516
export const MULTIPLE_POST_REACTIVE =
@@ -128,7 +129,12 @@ function getCurrentContainer() {
128129
if (instance) {
129130
const token = CONTAINER_TOKEN;
130131
const provides = instance.provides;
131-
if (provides && Object.prototype.hasOwnProperty.call(provides, token)) {
132+
const parentProvides = instance.parent && instance.parent.provides;
133+
if (
134+
provides &&
135+
provides !== parentProvides &&
136+
Object.prototype.hasOwnProperty.call(provides, token)
137+
) {
132138
return provides[token];
133139
}
134140
} else {

src/utils.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { interfaces } from 'inversify';
2+
import { ComponentInternalInstance } from 'vue';
3+
4+
/**
5+
* useService是从当前组件开始像父组件以及祖先组件查找服务实例
6+
* findService是从当前组件【不包含当前组件】向子组件以及后代组件查找服务实例
7+
* 可以通过component.container尝试获取该组件是否有绑定对应的inversify的container
8+
* 然后通过container.isBound(token)来判断是否有绑定对应的服务
9+
* 如果有绑定则通过container.get(token)来获取服务实例
10+
* 注意component.subTree.children是当前组件的子组件
11+
* 整个过程是一个递归的过程,因为子组件还有子组件,所以需要递归查找
12+
* @param component ComponentInternalInstance 当前组件
13+
* @param token interfaces.ServiceIdentifier<T> 服务标识
14+
*/
15+
export function findService<T>(
16+
component: ComponentInternalInstance,
17+
token: interfaces.ServiceIdentifier<T>
18+
): T | undefined {
19+
return (component as any);
20+
// const children = component.subTree.children;
21+
// if (children && Array.isArray(children)) {
22+
// for (let i = 0; i < children.length; i++) {
23+
// const child = children[i];
24+
// if (child && child.component) {
25+
// const container = child.component.container;
26+
// if (container && container.isBound(token)) {
27+
// return container.get(token);
28+
// } else {
29+
// return findService(child, token);
30+
// }
31+
// }
32+
// }
33+
// }
34+
}

tests/test19/ChildComp.vue

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<script setup lang="ts">
2+
import { declareProviders, useService } from '../../src/index';
3+
import { ChildService } from './ChildService';
4+
5+
declareProviders([ChildService]);
6+
const childService = useService(ChildService);
7+
8+
defineExpose({
9+
childService,
10+
});
11+
</script>
12+
13+
<template>
14+
<div>
15+
<div class="child-count">{{ childService.count }}</div>
16+
17+
<button
18+
type="button"
19+
class="btn-count-child"
20+
@click="childService.increaseCount()"
21+
>
22+
Add count child
23+
</button>
24+
</div>
25+
</template>

tests/test19/ChildService.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export class ChildService {
2+
public count = 1;
3+
4+
public increaseCount() {
5+
this.count++;
6+
}
7+
}

tests/test19/DemoComp.vue

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<script setup lang="ts">
2+
import {
3+
declareProviders,
4+
useService,
5+
CURRENT_COMPONENT,
6+
} from '../../src/index';
7+
import { DemoService } from './DemoService';
8+
import ChildComp from './ChildComp.vue';
9+
import { getCurrentInstance } from 'vue';
10+
11+
declareProviders([DemoService]);
12+
const demoService = useService(DemoService);
13+
14+
const component1 = useService(CURRENT_COMPONENT);
15+
const component2 = getCurrentInstance();
16+
17+
defineExpose({
18+
demoService,
19+
component1,
20+
component2,
21+
});
22+
</script>
23+
24+
<template>
25+
<div>
26+
<div class="demo-count">{{ demoService.count }}</div>
27+
28+
<button
29+
type="button"
30+
class="btn-count-demo"
31+
@click="demoService.increaseCount()"
32+
>
33+
Add count demo
34+
</button>
35+
</div>
36+
37+
<div class="child-1-container">
38+
<div class="child-1-wrapper">
39+
<ChildComp />
40+
</div>
41+
</div>
42+
43+
<div class="child-2-container">
44+
<div class="child-2-wrapper">
45+
<div class="child-2-box">
46+
<ChildComp />
47+
</div>
48+
</div>
49+
</div>
50+
</template>

tests/test19/DemoService.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export class DemoService {
2+
public count = 1;
3+
4+
public increaseCount() {
5+
this.count++;
6+
}
7+
}

tests/test19/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
## 测试场景
2+
3+
验证循环依赖,LazyServiceIdentifier 也不能解决循环依赖的问题
4+
5+
这是一个大问题,我以为属性注入器可以避免循环依赖已经是行业共识了,比如Spring中就是这么处理的。
6+
7+
但是inversify居然不是这么处理的,显然是收集完所有属性之后才会放入缓存系统。
8+
9+
比较简单的方案就是采用二级缓存,假设现在的缓存cache是最终的缓存结果。
10+
那么再增加一层tempCache,这个缓存只是临时存储实例化对象,方便被其他对象依赖时可以从缓存中获取该对象。

tests/test19/demo.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import 'reflect-metadata';
2+
import { mount } from '@vue/test-utils';
3+
import DemoComp from './DemoComp.vue';
4+
import { ChildService } from './ChildService';
5+
import { findService } from '../../src/index';
6+
7+
describe('test19', () => {
8+
it('get DemoService instance', async () => {
9+
const wrapper = mount(DemoComp);
10+
11+
expect(wrapper.vm.component1).toBe(wrapper.vm.component2);
12+
13+
const childService = findService(wrapper.vm.component1, ChildService);
14+
15+
// expect(childService).toBeInstanceOf(ChildService);
16+
17+
expect(1).toBe(1);
18+
});
19+
});

0 commit comments

Comments
 (0)