micke
micke

Reputation: 117

Vue + Apollo + Graphql + subscription + cache?

I have just started working with Apollo on my side project (web game) and got stuck on some of the subscriptions I use.

In some views the subscription doesn't run directly, but it works as expected if I refresh the page.

// StartGame.vue

<script>
import store from "../store/index";
export default {
  data() {
    return {
      players: [],
      game: null
    };
  },
  methods: {
    async onStartGame() {
      const response = await this.$store.dispatch("updateGame", {
        started: true
      });

      if (!response) {
        alert("Something went wrong. Try again");
        return;
      }

      this.$router.push({ name: "GameProgress" });
    },
    onGoToGame() {
      this.$router.push({ name: "GameProgress" });
    }
  },
  mounted() {
    this.game = this.$store.getters.getGame;
  },
  created() {
    this.$apollo.subscriptions.gameAndPlayers.refresh();
  },
  apollo: {
    $subscribe: {
      gameAndPlayers: {
        query: require("../graphql/subscriptions/subscribeGameAndPlayers.gql"),
        variables: {
          game_id: store.getters.getGame.id
        },
        result(data) {
          console.log("subscribeGameAndPlayers", data);
          const game = data.data.game;

          this.game = { ...this.game, started: game.started };
          this.players = game.players;
        }
      }
    }
  }
};
</script>

Can someone see something obvious wrong with this piece of code? As I wrote, if I refresh this page the subscription starts to work (players join the game from other browsers). I guess mounted and created isn't needed if I can get the apollo part to work, right?

I thought it's probably some cache since Apollo seems to use it a lot, and I don't have much knowledge about it yet.

Tried to add fetchPolicy: 'no-cache' without success

// apollo.js (included in main.js)

export default new ApolloClient({
  link: link
  cache: new InMemoryCache(),
  defaultOptions: {
    fetchPolicy: "no-cache"
  }
});

A few more views have the same behavior so I guess it's something fundamental I'm missing..

Upvotes: 1

Views: 1328

Answers (1)

micke
micke

Reputation: 117

I solved my problem. I was missing some fundamentals about vue-apollo as I thought..

In apollo, I fetch my data with a query first, and then add the subscription by subscribeToMore

There is probably a better way, but here is the working code:

//start game

<script>
import store from "../store/index";

export default {
  data() {
    return {
      gameAndPlayers: null,
      loading: 0
    };
  },
  methods: {
    async onStartGame() {
      const response = await this.$store.dispatch("updateGame", {
        started: true
      });

      if (!response) {
        alert("Something went wrong. Try again");
        return;
      }

      this.$router.push({ name: "GameProgress" });
    },
    onGoToGame() {
      this.$router.push({ name: "GameProgress" });
    }
  },
  apollo: {
    gameAndPlayers: {
      query: require("../graphql/queries/getGameAndPlayers.gql"),
      variables() {
        return {
          id: store.getters.getGame.id
        };
      },
      update(data) {
        return { ...data.game };
      },
      subscribeToMore: [
        {
          document: require("../graphql/subscriptions/subscribeGameAndPlayers.gql"),
          variables() {
            return {
              game_id: store.getters.getGame.id
            };
          },
          updateQuery: (previous, { subscriptionData }) => {
            return { ...subscriptionData.data };
          }
        }
      ]
    }
  }
};
</script>

I hope this might help someone else with the same problem.

Upvotes: 2

Related Questions