Skip to content

Commit

Permalink
增加测试用例-获取子组件服务
Browse files Browse the repository at this point in the history
  • Loading branch information
kaokei committed Nov 24, 2024
1 parent 5ea7a81 commit 464207d
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 1 deletion.
8 changes: 7 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
Plugin,
App,
} from 'vue';
export { findService } from './utils';

export const POST_REACTIVE = 'METADATA_KEY_POST_REACTIVE';
export const MULTIPLE_POST_REACTIVE =
Expand Down Expand Up @@ -128,7 +129,12 @@ function getCurrentContainer() {
if (instance) {
const token = CONTAINER_TOKEN;
const provides = instance.provides;
if (provides && Object.prototype.hasOwnProperty.call(provides, token)) {
const parentProvides = instance.parent && instance.parent.provides;
if (
provides &&
provides !== parentProvides &&
Object.prototype.hasOwnProperty.call(provides, token)
) {
return provides[token];
}
} else {
Expand Down
34 changes: 34 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { interfaces } from 'inversify';
import { ComponentInternalInstance } from 'vue';

/**
* useService是从当前组件开始像父组件以及祖先组件查找服务实例
* findService是从当前组件【不包含当前组件】向子组件以及后代组件查找服务实例
* 可以通过component.container尝试获取该组件是否有绑定对应的inversify的container
* 然后通过container.isBound(token)来判断是否有绑定对应的服务
* 如果有绑定则通过container.get(token)来获取服务实例
* 注意component.subTree.children是当前组件的子组件
* 整个过程是一个递归的过程,因为子组件还有子组件,所以需要递归查找
* @param component ComponentInternalInstance 当前组件
* @param token interfaces.ServiceIdentifier<T> 服务标识
*/
export function findService<T>(
component: ComponentInternalInstance,
token: interfaces.ServiceIdentifier<T>

Check failure on line 17 in src/utils.ts

View workflow job for this annotation

GitHub Actions / build

'token' is declared but its value is never read.

Check failure on line 17 in src/utils.ts

View workflow job for this annotation

GitHub Actions / build

'token' is declared but its value is never read.
): T | undefined {
return (component as any);
// const children = component.subTree.children;
// if (children && Array.isArray(children)) {
// for (let i = 0; i < children.length; i++) {
// const child = children[i];
// if (child && child.component) {
// const container = child.component.container;
// if (container && container.isBound(token)) {
// return container.get(token);
// } else {
// return findService(child, token);
// }
// }
// }
// }
}
25 changes: 25 additions & 0 deletions tests/test19/ChildComp.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<script setup lang="ts">
import { declareProviders, useService } from '../../src/index';
import { ChildService } from './ChildService';
declareProviders([ChildService]);
const childService = useService(ChildService);
defineExpose({
childService,
});
</script>

<template>
<div>
<div class="child-count">{{ childService.count }}</div>

<button
type="button"
class="btn-count-child"
@click="childService.increaseCount()"
>
Add count child
</button>
</div>
</template>
7 changes: 7 additions & 0 deletions tests/test19/ChildService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export class ChildService {
public count = 1;

public increaseCount() {
this.count++;
}
}
50 changes: 50 additions & 0 deletions tests/test19/DemoComp.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<script setup lang="ts">
import {
declareProviders,
useService,
CURRENT_COMPONENT,
} from '../../src/index';
import { DemoService } from './DemoService';
import ChildComp from './ChildComp.vue';
import { getCurrentInstance } from 'vue';
declareProviders([DemoService]);
const demoService = useService(DemoService);
const component1 = useService(CURRENT_COMPONENT);
const component2 = getCurrentInstance();
defineExpose({
demoService,
component1,
component2,
});
</script>

<template>
<div>
<div class="demo-count">{{ demoService.count }}</div>

<button
type="button"
class="btn-count-demo"
@click="demoService.increaseCount()"
>
Add count demo
</button>
</div>

<div class="child-1-container">
<div class="child-1-wrapper">
<ChildComp />
</div>
</div>

<div class="child-2-container">
<div class="child-2-wrapper">
<div class="child-2-box">
<ChildComp />
</div>
</div>
</div>
</template>
7 changes: 7 additions & 0 deletions tests/test19/DemoService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export class DemoService {
public count = 1;

public increaseCount() {
this.count++;
}
}
10 changes: 10 additions & 0 deletions tests/test19/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
## 测试场景

验证循环依赖,LazyServiceIdentifier 也不能解决循环依赖的问题

这是一个大问题,我以为属性注入器可以避免循环依赖已经是行业共识了,比如Spring中就是这么处理的。

但是inversify居然不是这么处理的,显然是收集完所有属性之后才会放入缓存系统。

比较简单的方案就是采用二级缓存,假设现在的缓存cache是最终的缓存结果。
那么再增加一层tempCache,这个缓存只是临时存储实例化对象,方便被其他对象依赖时可以从缓存中获取该对象。
19 changes: 19 additions & 0 deletions tests/test19/demo.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import 'reflect-metadata';
import { mount } from '@vue/test-utils';
import DemoComp from './DemoComp.vue';
import { ChildService } from './ChildService';
import { findService } from '../../src/index';

describe('test19', () => {
it('get DemoService instance', async () => {
const wrapper = mount(DemoComp);

expect(wrapper.vm.component1).toBe(wrapper.vm.component2);

const childService = findService(wrapper.vm.component1, ChildService);

Check failure on line 13 in tests/test19/demo.test.ts

View workflow job for this annotation

GitHub Actions / build

'childService' is declared but its value is never read.

// expect(childService).toBeInstanceOf(ChildService);

expect(1).toBe(1);
});
});

0 comments on commit 464207d

Please sign in to comment.