不同场景
场景
场景 1:一个服务可以被多个组件绑定,一个组件也可以绑定多个服务
这里说的绑定是指调用declareProviders
方法,背后的逻辑是创建了一个独立的 container,所以就算是同一个服务,被不同的组件绑定,那么生成的服务实例也是不一样的。
如果想要不同的组件共享同一个服务实例,那么应该将这个服务提升到这些组件的公共祖先组件中进行绑定,自然所有子孙组件都可以获取到相同的服务实例对象了。
这里的绑定还有另一层含义,就是一旦组件被卸载,该组件绑定的所有服务也会被释放。
组件和服务之间不会出现以下场景:
- 同一个组件实例关联多个相同的服务实例
- 同一个服务实例关联多个组件实例
目前可行的一个 Workaround 是采用别名的方式引用同一个服务实例。也就是container.bind(别名).toService(服务名)
。 这样我们就可以给同一个服务绑定多个不同的别名。这些别名会指向同一个服务实例对象。
场景 2:组件中可以访问自身绑定的服务
可以通过useService(token)
获取对应的服务实例对象。
注意这里useService(token)
一定需要在declareProviders([token])
之后。也就是需要先声明绑定关系,再实例化服务。
场景 3:服务可以访问绑定的组件
原本是想着可以直接在服务中可以通过组件访问 props,emit 等属性。
最终还是决定保持服务的独立性,服务只关心数据,以及修改数据的方法。不应该关心哪个组件在使用。
应该是组件去使用和更新服务的数据,而不是服务去调用组件的方法。
场景 4:子组件获取父组件的服务
【推荐】最好是解耦父组件服务的引用,也就是通过 token 来获取父组件的服务,而不是直接使用父组件的服务名作为 token。
【不推荐】直接使用父组件的服务名作为 token 来获取父组件的服务。虽然不推荐,但是副作用也仅仅是降低子组件的复用性而已。 如果我们再定义子组件时就已经确定这个子组件只会在这一个父组件中使用,其实也并不是大问题。
场景 5:父组件获取子组件的服务
【推荐】通过 findService 实时查找子组件对应的服务。可以跨多个组件层级获取深层子组件的服务。
【推荐】通过 ref 获取子组件实例,然后通过子组件实例访问子组件服务。需要依赖 defineExpose 暴露相应的服务实例。
缺点是只能获取父组件自身的子组件,不能获取更深层的子组件对应的服务。【强烈禁止】这种方案是将子组件的服务绑定到父组件上,也就是将子组件的服务当作父组件的服务来使用。这样父组件和子组件都能获取到这个服务实例了。
缺点是明明是子组件的服务,却绑定在父组件上。最终导致该服务的生命周期和子组件不一致。
另一个缺点是组件服务的作用域非常不清晰,代码维护成本过高。后续删除子组件时,很容易忘记删除对应的服务。