使用 Apollo 客户端和 Vue 使用反应变量进行状态管理

状态管理是软件开发中不可或缺的一部分,使用VueX、 Pania(如VueX 5)、ReduxContext API等工具。

在我们的示例中,我们将使用Vue3 组合 API,以及一些TypeScript

本文将假设您已经使用 Apollo 进行了项目设置。

状态管理

在我们深入了解状态管理是什么以及它提供什么之前,让我们先了解一些与它不可分割的东西。

什么是状态?

状态是应用程序的一部分,例如用户详细信息、用户名、登录信息和网站主题(深色或浅色)。

简单来说,状态就像一个仓库,您可以随时随地访问其中的内容。

什么是状态管理?

状态管理只是一种简单的设计模式,用于帮助在应用程序中的所有组件中同步应用程序的状态。这也可以防止我们在应用程序中传递过多的道具。

何时实施状态管理:

  • 当应用程序包含大量组件时。
  • 为了防止冗余数据,了解其他一些组件可能需要这些数据。
  • 防止在应用程序中传递道具,使其变得混乱。

如何实施状态管理?

有很多方法可以做到这一点。但在本次讨论中,我们将使用Vue Apollo来实现它。

Apollo 客户端

它是Vue Apollo的客户端。它有助于在您的应用程序中轻松集成 GraphQL 查询和突变,在我们的例子中,它是 Vue。

反应变量

这是 Apollo Client 3 的一项新功能。

反应变量是一种有用的机制,用于在 Apollo 客户端缓存之外表示本地状态。

如何在 Apollo 中创建 Reactive 变量?

这很简单,因为 Apollo 客户端为我们提供了makeVar.


import { makeVar } from '@apollo/client';

const counts = makeVar(0);
console.log(counts());
// Output: 0

/* Update the value of counts */
counts(1);
console.log(counts());
// Output: 1

const cartItemsVar = makeVar([]);
console.log(cartItemsVar());
// Output: []

/* Update the value of cartItemsVar */
cartItemsVar(['Vue', 'Apollo', 'State Management']);
console.log(cartItemsVar());
// Output: ['Vue', 'Apollo', 'State Management']

const isLoggedIn = makeVar(false);
console.log(isLoggedIn());
//  Output: false

/* Update the value of isLoggedIn */
isLoggedIn(true);
console.log(isLoggedIn());
// Output: true

上面代码的意思是我们使用 makeVar 来创建任何类型的变量,无论是booleannumberarray还是object。此外,通过调用分配给 makeVar 的变量而不传递参数只会输出其当前值,但传递参数将更新其值。

您可以在此处了解有关 makeVar的更多信息。

项目设置

我们将为增加、减少或重置的计数器创建一个状态。但首先,让我们设置我们的环境。

设置反应变量

让我们在以下位置创建我们的反应变量./variables/counts.js


import { makeVar } from '@apollo/client';

export const counts = makeVar(0);

配置缓存

让我们也将我们的缓存配置更新为如下内容:


// Need to import the variable we reated
import { counts } from '../variables/counts';

// Cache implementation
const cache = new InMemoryCache({
  typePolicies: {
    Query: {
      fields: {
        count: { //The name we will be querying
          read() {
            return counts(); //Returns the updated value of counts
          },
        },
      },
    },
  },
});

创建组件

让我们创建./components/Counter.vue组件:


<template>
  <div>
    <div class="col-3">
      <h6>
        Count: <span v-if="!loading">{{ count }}</span>
      </h6>
    </div>
    <div class="col-3">
      <button @click="increment">Increment</button>
    </div>
    <div class="col-3">
        <button @click="decrement">Decrement</button>
    </div> 
    <div class="col-3">
      <button @click="reset">Reset</button>
    </div>

  </div>
</template>

<script lang="ts">
import { computed, defineComponent } from 'vue';

export default defineComponent({
  name: 'NumberCounter',
});
</script>

<script lang="ts" setup>
import { counts } from 'src/variables/counts';
import { useQuery } from '@vue/apollo-composable';
import gql from 'graphql-tag';

// This is to fetch the count value using the query
const COUNTERS_QUERY = gql`
  query Counter {
    count @client
  }
`;

const { result, loading } = useQuery(COUNTERS_QUERY);

const count = computed(() => (result.value ? result.value.count : 0));

const increment = () => {
  let cnts = counts();
  cnts++;
  counts(cnts);
};

const decrement = () => {
  let cnts = counts();
  cnts--;
  counts(cnts);
};

const reset = () => {
  cnts= 0;
  counts(cnts);
};

</script>

请注意,即使没有 GraphQL 查询,您也始终可以获得计数值。您需要做的就是count()像关于Reactive variables的示例一样调用,并使用 loading 作为 ref 强制重新渲染。

像这样:


 <template>
  <div>
    <div class="col-3">
      <h6>
        Count: <span v-if="!loading">{{ counts() }}</span>
      </h6>
    </div>
    <div class="col-3">
      <button @click="increment">Increment</button>
    </div>
    <div class="col-3">
        <button @click="decrement">Decrement</button>
    </div> 
    <div class="col-3">
      <button @click="reset">Reset</button>
    </div>

  </div>
</template>

<script lang="ts">
import { ref, defineComponent } from 'vue';

export default defineComponent({
  name: 'NumberCounter',
});
</script>

<script lang="ts" setup>
import { counts } from 'src/variables/counts';
// loading ref to help re-render when there is a change so as to get the latest value of counts.
const loading = ref(false);

const increment = () => {
  let cnts = counts();
  loading.value = true;
  cnts++;
  counts(cnts);
  loading.value = false;
};

const decrement = () => {
  let cnts = counts();
  loading.value = true;
  cnts--;
  counts(cnts);
  loading.value = false;
};

const reset = () => {
  cnts = 0;
  loading.value = true;
  counts(cnts);
  loading.value = false;
};

</script>

加载 ref 以帮助在发生更改时重新渲染,从而获得最新的计数值。

您喜欢的方式取决于您想要实现的目标。但是我将使用带有查询的示例,因为它仍然保留了 GraphQL 的感觉。

结论

只要应用程序使用 Apollo,使用 Apollo 客户端进行状态管理就可以为您节省安装 VueX 或 Redux(对于 React 用户)的压力。在这个快速培训中,我们了解了状态以及为什么状态管理对于构建和维护应用程序很重要。