前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[译] 用 Vue 3 Composition API 实现 React Context/Provider 模式

[译] 用 Vue 3 Composition API 实现 React Context/Provider 模式

作者头像
江米小枣
发布2020-07-06 09:45:51
1.6K0
发布2020-07-06 09:45:51
举报
文章被收录于专栏:云前端云前端

原文: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 中,我们已经拥有了可以快速复刻前者功能的所有必需工具。

用户设置 provider

在本例中,来看看如何运用这一模式 让某些信息全局可用

如下的 ProvideUserSettings 组件,提供了一个反应式的 state 及一些默认值,还有一个 update() 函数用以设置 state 对象。

代码语言:javascript
复制
// 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 组件:

代码语言:javascript
复制
<!-- src/App.vue -->

<script>
import ProvideUserSettings from './components/ProvideUserSettings';

export default {
  name: 'App',
  components: {
    ProvideUserSettings,
  },
};
</script>

<template>
  <ProvideUserSettings>
    <div>
      <!-- ... -->
    </div>
  </ProvideUserSettings>
</template>

或许在遍及应用各处的多个组件中都需要这个设置。因此,将 provider 置于顶层的 App 组件中很有必要。

如此一来在组件树中的任意位置都能访问到该用户设置了。

代码语言:javascript
复制
<!-- 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() 过的上下文中 消费 用户设置状态 了。

接下来的例子中,将演示如何在应用中的任意组件里 更新 该状态:

代码语言:javascript
复制
<!-- 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() 了该状态的组件也都将被更新

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-07-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云前端 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 用户设置 provider
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档