本文寫於 2021 年 2 月 19 日html
在 React 中,咱們能夠經過 context 與 useContext 實現單例、注入……等諸多特性。vue
詳細請看上一篇文章:如何利用 React Hooks 管理全局狀態.dom
例如:ide
const SomeService = createContext(null); const useRootSomeService = () => { const [n, setN] = useState(0); const add = useCallback(() => { setN((number) => number + 1); }, []); return { n, setN }; }; const App: React.FC = () => { return ( <SomeService.Provider value={useRootSomeService()}> <Apple /> </SomeService> ) }; const Apple: React.FC = () => { const someService = useContext(SomeService) };
那麼 Vue3 能夠嗎?this
能夠!!!只須要利用 Vue3 的 provide 與 inject API 即。code
import { Ref, ref } from "vue"; class ChatService { static INJECT_KEY: string; conversations: Ref<Conversation[]>; constructor() { this.conversations = ref([]); } }
這樣咱們只須要在組件中實例化該 class,就能夠擁有響應性的 conversations 屬性了。htm
可是咱們不知足於如此,咱們還想要在任何地方,均可以使用 const chatService = inject(ChatService);
來拿到服務的單例!blog
vue3 提供給咱們的 provide API 能夠在任意組件中使用:provide(key, variable);
get
使用後該組件的自組件的任何位置均可以利用 inject API 拿到剛剛注入的變量:const v = inject(key);
。string
所以咱們能夠這麼封裝一下:
import { provide as vueProvide, inject as vueInject } from "vue"; export const createInjectKey = () => { const randomNumber = Math.round(Math.random() * 10 ** 8).toString(); return randomKey; }; interface ServiceType<T> { new (): T; INJECT_KEY: string; } export function provide<T>(Service: ServiceType<T>) { const key = createInjectKey(); Service.INJECT_KEY = key; vueProvide(key, new Service()); } export function inject<T>(Service: ServiceType<T>): T { const service = vueInject<T>(Service.INJECT_KEY); if (!service) { console.error("You have to provide service first!!!"); } return service!; }
這樣一來,咱們只須要寫一個擁有 static INJECT_KEY 屬性的 class,就能夠在組件樹頂端使用 provide(xxxService)
,而後再在任意位置調用 inject(xxxService)
來獲取服務單例了!
(完)