来自 Vuex 的 Apollo 请求

Posted

技术标签:

【中文标题】来自 Vuex 的 Apollo 请求【英文标题】:Apollo request from Vuex 【发布时间】:2020-07-28 21:55:02 【问题描述】:

谁能告诉我可以从哪里导入apolloClient 以便我可以向 apollo 发出请求? 我通常会收到一个错误,要么 mutate is not a function(即使我从 Vue 组件传入this.$apollo

我只是想进入 Vue 的方式。如果有任何关于代码和结构的提示,我将不胜感激

登录组件

<template>
  <div class="signIn-component">
    <form @submit.prevent="signInUser()">
      <input
        type="email"
        placeholder="Enter your email"
        v-model="formInput.email"
      />
      <input
        type="password"
        placeholder="Enter your password"
        v-model="formInput.password"
      />
      <button>Sign In</button>
    </form>
  </div>
</template>

<script>
import  createNamespacedHelpers  from "vuex";

const  mapActions  = createNamespacedHelpers("auth");

export default 
  data() 
    return 
      formInput: 
        email: null,
        password: null
      
    ;
  ,
  methods: 
    // Vuex Actions
    ...mapActions(["signIn"]),
    signInUser: function() 
      // eslint-disable-next-line no-unused-vars
      this.signIn(this.formInput, this.$apollo).then(_ =>
        this.$route.push("/")
      );
    
  
;
</script>

<style></style>


Vuex.auth

import  apolloClient  from 'vue-cli-plugin-apollo/graphql-client';
import SignInGQL from "@/graphql/signIn.gql";

export default 
    namespaced: true,
    state: 
        token: null,
        user: ,
        authStatus: false
    ,
    getters: 
        isAuthenticated: state => !!state.token,
        authStatus: state => state.authStatus,
        user: state => state.user
    ,
    actions: 
        async signIn( commit, dispatch , formInput) 

            console.log('here');
            try 
                const  data  = await apollo.mutate(
                    mutation: SignInGQL,
                    variables:  ...formInput 
                )

                const  token  = data.signIn;
                console.log(token);
                commit('setToken', token);
                localStorage.setItem('auth-token', token);
                dispatch('setUser', token);
             catch (e) 
                console.error(e)
            
        ,
        setUser( commit , token) 
            const encodedPayload = token.split('.')[1];

            const  payload  = JSON.parse(atob(encodedPayload));
            console.log('payload: ', payload);

            // TODO: Set User information 
            commit('signInUser', payload);
        
    ,
    mutations: 
        setToken(state, token) 
            state.token = token
        ,
        signInUser(state, user) 
            state.authStatus = true
            state.user =  ...user 
        ,
        // logOutUser(state) 
        //     state.authStatus = ''
        //     state.token = '' && localStorage.removeItem('auth-token')
        // 
    


【问题讨论】:

【参考方案1】:

This question explains adding headers to apollo client

solution repo

import  setContext  from "apollo-link-context";
import  ApolloClient, InMemoryCache, HttpLink  from "apollo-boost";
import VueApollo from "vue-apollo";

Vue.use(VueApollo);
const httpLink = new HttpLink(
  uri: "http://sebapi.com/graphql"
);
const authLink = setContext((_,  headers ) => 
  // get the authentication token from ApplicationSettings if it exists
  const token = ApplicationSettings.getString("token");
  // return the headers to the context so HTTP link can read them
  return 
    headers: 
      ...headers,
      authorization: token ? `Bearer $token` : null
    
  ;
);
// update apollo client as below
const apolloClient = new ApolloClient(
  link: authLink.concat(httpLink),
  cache: new InMemoryCache()
);

const apolloProvider = new VueApollo(
  defaultClient: apolloClient
);

和 LOGIN.VUE

<script lang="ts">

export default 
  data() 
    return 
      jwt: "",
      user: 
        identifier: "test",
        password: "123123",
      ,
    ;
  ,
  methods: 
    handleLogin() 

      request(
        url: "http://sebapi.com/auth/local",
        method: "POST",
        headers:  "Content-Type": "application/json" ,
        content: JSON.stringify(
          identifier: this.user.identifier,
          password: this.user.password,
        ),
      )
        .then(
          (response) => 
            const result = response.content.toJSON();
            console.log("Result from Server: ", result);
//ignore applicationsettings it's just a kind of localstore in nativescript
            ApplicationSettings.setString("token", result.jwt);           
          ,
          (e) => 
            console.error(e);
//ignore nativateto its routing in nativescript
            this.$navigateTo(routes.login);
          
        )
        .then(() => 
          this.$navigateTo(routes.app);
        );
    ,
  ,
;
</script>

【讨论】:

默认情况下,Vue-Apollo 文件导出函数“createProvider”(如果您使用 Vue Apollo 的 cli 版本)。而持有 ApolloClient 的“createApolloClient”在“createRrovider”中被声明。我将 createApolloClient 移到了 CreateProvider 之外,将其导出到那里,然后将其导入到我的商店文件中。默认情况下,标题是在后台实现的。我只是简单地添加了我保存令牌的 localStorage 文件的名称。我在 Vuex 存储中使用 Apollo 时遇到了麻烦。我不想修补自己的实现,因为我使用了 Vue-Apollo 您是否使用其他路由器而不是 Vue 内置路由器?我注意到“this.$navigateTo”。或者您只是全局分配了自己的导航服务?我是这个框架的新手——很多关于实践和经验的问题 @Valaryo 这只是在 nativescript-vue 中导航的另一种方式Manual routing 我知道了。谢谢!【参考方案2】:

我就是这样做的,以防有人正在寻找相同的答案:

import Vue from 'vue'
import VueApollo from 'vue-apollo'
import  createApolloClient  from 'vue-cli-plugin-apollo/graphql-client'

// Install the vue plugin
Vue.use(VueApollo)

// Name of the localStorage item
const AUTH_TOKEN = 'auth-token'

// Http endpoint
const httpEndpoint = process.env.VUE_APP_GRAPHQL_HTTP || 'http://localhost:3000/graphql';

// Config
const defaultOptions = 
  // You can use `https` for secure connection (recommended in production)
  httpEndpoint,
  // You can use `wss` for secure connection (recommended in production)
  // Use `null` to disable subscriptions
  wsEndpoint: process.env.VUE_APP_GRAPHQL_WS || null,
  // wsEndpoint: process.env.VUE_APP_GRAPHQL_WS || 'ws://localhost:3000/graphql',
  // LocalStorage token
  tokenName: AUTH_TOKEN,
  // Enable Automatic Query persisting with Apollo Engine
  persisting: false,
  // Use websockets for everything (no HTTP)
  // You need to pass a `wsEndpoint` for this to work
  websocketsOnly: false,
  // Is being rendered on the server?
  s-s-r: false,

  // Override default apollo link
  // note: don't override httpLink here, specify httpLink options in the
  // httpLinkOptions property of defaultOptions.
  // httpLinkOptions: 
  //   headers: 
  //     Authorization: authHeader
  //   
  // 

  // Override default cache
  // cache: myCache

  // Override the way the Authorization header is set
  // getAuth: (tokenName) => getUserToken(),

  // Additional ApolloClient options
  // apollo:  ... 

  // Client local data (see apollo-link-state)
  // clientState:  resolvers:  ... , defaults:  ...  


export const  apolloClient, wsClient  = createApolloClient(
  ...defaultOptions,
  // ...options,
)

// Call this in the Vue app file
export function createProvider() 
  // Create apollo client

  apolloClient.wsClient = wsClient

  // Create vue apollo provider
  const apolloProvider = new VueApollo(
    defaultClient: apolloClient,
    defaultOptions: 
      $query: 
        fetchPolicy: 'cache-and-network',
      ,
    ,
    errorHandler(error) 
      // eslint-disable-next-line no-console
      console.log('%cError', 'background: red; color: white; padding: 2px 4px; border-radius: 3px; font-weight: bold;', error.message)
    ,
  )

  return apolloProvider



This is the source I found the solution

如果您有任何建议,请随时将它们留在此处!

【讨论】:

以上是关于来自 Vuex 的 Apollo 请求的主要内容,如果未能解决你的问题,请参考以下文章

Apollo 客户端 fetchMore 来自 useQuery 触发两个网络请求

如何用 apollo 客户端状态管理替换 vuex?

使用 Apollo 和 GraphQL 缓存而不是 Vuex?

markdown 在Vuex中使用apollo的最佳实践

如何在前端 apollo-client 上处理来自 Node/Koa 的后端错误

我可以使用 Nuxt Apollo 本地状态来完全替换 Vuex 吗?