原文:https://markus.oberlehner.net/blog/context-and-provider-pattern-with-the-vue-3-composition-api/
React Context API 提供了一种 不用在组件树中逐层传递 props (也称 prop drilling)的前提下 共享被多个组件都需要的属性 (比如用户设置、UI 主题等)的方式。尽管 Vue.js 没有自带的完全一致的抽象,但在本文中,我们将看到 在 Vue 3 中,我们已经拥有了可以快速复刻前者功能的所有必需工具。
在本例中,来看看如何运用这一模式 让某些信息全局可用。
如下的 ProvideUserSettings
组件,提供了一个反应式的 state
及一些默认值,还有一个 update()
函数用以设置 state
对象。
// src/components/ProvideUserSettings.js
import {
provide,
reactive,
readonly,
toRefs,
} from 'vue';
// 使用 symbols 制造独特标识
export const UserSettingsStateSymbol = Symbol('User settings state provider identifier');
export const UserSettingsUpdateSymbol = Symbol('User settings update provider identifier');
export default {
setup() {
const state = reactive({
language: 'en',
theme: 'light',
});
// 使用 `toRefs()` 确保其在消费者组件中广泛可用
// 而 `readonly()` 预防了用户修改全局状态
provide(UserSettingsStateSymbol, toRefs(readonly(state)));
const update = (property, value) => {
state[property] = value;
};
provide(UserSettingsUpdateSymbol, update);
},
render() {
// 该 provider 组件是 “renderless” 的
// 其自身不渲染任何东西
return this.$slots.default();
},
};
下面来看看如何在应用中使用 ProvideUserSettings
组件:
<!-- src/App.vue -->
<script>
import ProvideUserSettings from './components/ProvideUserSettings';
export default {
name: 'App',
components: {
ProvideUserSettings,
},
};
</script>
<template>
<ProvideUserSettings>
<div>
<!-- ... -->
</div>
</ProvideUserSettings>
</template>
或许在遍及应用各处的多个组件中都需要这个设置。因此,将 provider 置于顶层的 App
组件中很有必要。
如此一来在组件树中的任意位置都能访问到该用户设置了。
<!-- src/components/ButtonPrimary.vue -->
<script>
import { inject } from 'vue';
import { UserSettingsStateSymbol } from './ProvideUserSettings';
export default {
setup() {
const { theme } = inject(UserSettingsStateSymbol);
return { theme };
},
};
</script>
<template>
<ButtonBase
:class="$style[`t-${theme}`]"
>
<slot/>
</ButtonBase>
</template>
<style module>
.t-light { /* ... */ }
.t-dark { /* ... */ }
</style>
如上所示,我们已经看到了如何在 inject() 过的上下文中 消费 用户设置状态 了。
接下来的例子中,将演示如何在应用中的任意组件里 更新 该状态:
<!-- src/components/ThemeSwitcher.vue -->
<script>
import { inject } from 'vue';
import { UserSettingsUpdateSymbol } from './ProvideUserSettings';
export default {
setup() {
const updateUserSettings = inject(UserSettingsUpdateSymbol);
const updateTheme = value => updateUserSettings('theme', value);
return { updateTheme };
},
};
</script>
<template>
<div>
<button @click="updateTheme('dark')">
Enable darkmode
</button>
<button @click="updateTheme('light')">
Enable lightmode
</button>
</div>
</template>
这一次我们通过 UserSettingsUpdateSymbol
来 inject() 得到 provider 中的 update()
函数,并将其包裹在一个新的 updateTheme()
函数中,用来直接设置用户设置对象中的 theme
属性。
当两个按钮之一被点击,用户设置就被更新了,并且 因为该状态是一个反应式对象,所有 inject() 了该状态的组件也都将被更新。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有