Replies: 9 comments
-
@rdunk the way that we handle this is to use vuex for things that are related to routing (permissions, flags, etc) and use apollo more for fetching data in that context. I do agree that it would be great to tie into the vue lifecycles more fully but i think that would be a bigger change. |
Beta Was this translation helpful? Give feedback.
-
I'm running into an issue, using Basically, if I hit the following page directly, SSR will make sure that // pages/todos.vue
<template>
<section>Todos count: {{ todos.length }}</section>
</template>
<script>
import gql from "graphql-tag";
const TODOS_QUERY = gql`
query {
todos {
id
title
}
}
`;
export default {
apollo: {
todos: {
query: TODOS_QUERY
}
}
};
</script> Right now I'm using the Apollo client directly via Nuxt's |
Beta Was this translation helpful? Give feedback.
-
@Merott could you setup an small example demoing this? |
Beta Was this translation helpful? Give feedback.
-
@Austio Sure. Here it is: https://github.com/Merott/demo-vue-apollo-issue-762 |
Beta Was this translation helpful? Give feedback.
-
@Merott thanks for setting up an example for this. I can't express how much easier it makes it to help. I can see how this would be confusing. Vue issueAt it's core for vue, this is an issue related to having good defaults for anything that will go in the template and handling state as it changes. You can reproduce the error you see by deleting everything in the "script" section of "todos.vue" and then doing a client side navigation. Both scenarios look like this to vue
More specifically on your example that fails for todos
Why does this work sometimesThis works on SSR because
This works with asyncData because
The core issue for Apollo to me is that there isn't a tight integration of the "interface" between how things will work on the server vs will work on the client. However, that is a really big ask because it would make a lot of assumptions. Most of this will be much better once apollo-composable is the way things work because there will be way less magic. How to fixSo the issue with this is related to having good default values for loading and ensuring things are present before they are rendered. Here is a diff that works on client and server. The only real technical recommendation i have is to make sure you init data with the values you expect to be there from apollo
TO get a better grasp on this, you can add a watch on
|
Beta Was this translation helpful? Give feedback.
-
@Merott the pattern my team has adopted is to use // pages/todos.vue
<template>
<section>Todos count: {{ todos.length }}</section>
</template>
<script>
import gql from "graphql-tag";
const TODOS_QUERY = gql`
query {
todos {
id
title
}
}
`;
export default {
data() {
return {
todos: [],
}
},
async asycData(context) {
const client = context.app.apolloProvider.defaultClient;
const response = await client.query(TODOS_QUERY);
return {
todos: response.data.todos
};
}
};
</script> By returning the results from the query, there’s a chance you might duplicate the in-page hydration cache, in which case you could remove the return from // pages/todos.vue
<template>
<section>Todos count: {{ todos.length }}</section>
</template>
<script>
import gql from "graphql-tag";
const TODOS_QUERY = gql`
query {
todos {
id
title
}
}
`;
export default {
data() {
return {
todos: [],
}
},
async asycData(context) {
const client = context.app.apolloProvider.defaultClient;
await client.query(TODOS_QUERY);
}
apollo: {
todos: {
query: TODOS_QUERY,
fetchPolicy: ‘cache-only’
}
}
};
</script> We’ve had pretty good success with this approach. I would love it if there were a way to do this automatically via Vue Apollo, but I’m not sure that would be practical because it would be difficult to predict which queries should be fetched this way. For example, in complex parts of our application we will bundle up queries that are necessary for determining then a page is “loaded” into our Your mileage may vary, but it’s an approach that’s working for us. |
Beta Was this translation helpful? Give feedback.
-
@Austio thanks for the explanation. What I was in fact trying to avoid was having to implement a @gwardwell interesting approach, thanks for sharing. I gave that a try in the demo project that I set up, and it seems to work. Will give it a try in my project later to see how it goes. Thanks! |
Beta Was this translation helpful? Give feedback.
-
Can I bump this a bit? Even having a promise on |
Beta Was this translation helpful? Give feedback.
-
You can work around with a composable: import type { Ref } from 'vue';
import { watch } from '#imports';
export const useClientPrefetch = async (loading: Ref<boolean> | Array<Ref<boolean>>) => {
if (process.client) {
if (!Array.isArray(loading)) {
loading = [ loading ];
}
if (!loading.length) {
return;
}
await new Promise<void>((resolve) => {
watch(loading, () => {
let loaded = true;
for (let i = 0, len = (loading as Array<Ref<boolean>>).length; i < len; i++) {
if ((loading as Array<Ref<boolean>>)[ i ].value) {
loaded = false;
break;
}
}
if (loaded) {
resolve();
}
}, { immediate: true });
});
}
}; In your component: <script lang="ts">
export default defineComponent({
async setup() {
const { result, loading } = useQuery(QueryDocument);
await useClientPrefetch(loading);
}
}
</script> |
Beta Was this translation helpful? Give feedback.
-
This is along the same lines are #187, but I believe the plugin's internal API has changed since that issue was opened so the title is outdated. Also possibly related to #441.
I have an SSR app using this plugin alongside the the SSR plugin. I use the asyncData method to resolve non-Apollo async API requests on the server side and also before route components are resolved on the client side. Currently most route changes in the app await the result of the asyncData method before resolving and show a loading indicator before any content is displayed, but routes that use Apollo instead of asyncData resolve immediately with a flash of either empty or outdated content, execute the query and then update.
This plugin currently uses Vue's
serverPrefetch
method to resolve Apollo queries on the server, but I am struggling to find a way to ensure queries are executed on the client side before routes are resolved. It may be possible to execute queries manually in the asyncData method, but it seems that approach isn't recommended as you lose a lot of nice features this plugin provides.Is anyone able to provide a solution for this?
Beta Was this translation helpful? Give feedback.
All reactions