apollo icon indicating copy to clipboard operation
apollo copied to clipboard

Variables are not reactive (apollo-composable)

Open jan-demsar opened this issue 4 years ago • 13 comments

Describe the bug Updating variables does not trigger refetching data in vue-composable as described here: https://v4.apollo.vuejs.org/guide-composable/query.html#variables-ref.

I tried updating value of variable by extracting variables from the query const { result, variables } = useQuery(, passing "ref" and "reactive" variables, but nothing seems to be triggering update.

It works well with Options API and Vue Components but not with Composition API.

To Reproduce I created a sandbox :https://codesandbox.io/s/vue-composable-variables-problem-ozxjf?file=/src/components/Pokemon.vue .

There is an input field and button that triggers updating variable that was passed to query.

Variable updates correctly, but nothing happens with the query.

Expected behavior When changing variables, query should be refetched and new results should be displayed.

Versions vue: 2.6.11 @vue/apollo-composable: 4.0.0-alpha.8 apollo-boost: 0.4.7

Additional context Add any other context about the problem here.

jan-demsar avatar Apr 10 '20 14:04 jan-demsar

Try:

useQuery(
      gql`
        query pokemons($first: Int!) {
          pokemons(first: $first) {
            id
            name
          }
        }
      `,
      queryVariables
    )

Akryum avatar Apr 10 '20 15:04 Akryum

@Akryum thanks for the reply. I updated the codesandbox with your suggestion, but it is still the same.

Now I see the error:

[Vue warn]: Error in event handler for "hook:updated": "TypeError: Cannot read property 'nextTick' of undefined"

TypeError: Cannot read property 'nextTick' of undefined
    at baseRestart (https://yc7nf.csb.app/node_modules/@vue/apollo-composable/dist/useQuery.js:181:23)
    at restart (https://yc7nf.csb.app/node_modules/@vue/apollo-composable/dist/useQuery.js:213:9)
    at composition_api_1.watch.deep (https://yc7nf.csb.app/node_modules/@vue/apollo-composable/dist/useQuery.js:228:13)
    at applyCb (https://yc7nf.csb.app/node_modules/@vue/composition-api/dist/vue-composition-api.js:938:9)
    at Array.eval (https://yc7nf.csb.app/node_modules/@vue/composition-api/dist/vue-composition-api.js:897:20)
    at flushQueue (https://yc7nf.csb.app/node_modules/@vue/composition-api/dist/vue-composition-api.js:824:21)
    at VueComponent.flushPostQueue (https://yc7nf.csb.app/node_modules/@vue/composition-api/dist/vue-composition-api.js:790:5)
    at invokeWithErrorHandling (eval at Kr (https://codesandbox.io/static/js/sandbox.03d74bce7.js:1:180898), <anonymous>:1859:26)
    at VueComponent.Vue.$emit (eval at Kr (https://codesandbox.io/static/js/sandbox.03d74bce7.js:1:180898), <anonymous>:3885:9)
    at callHook (eval at Kr (https://codesandbox.io/static/js/sandbox.03d74bce7.js:1:180898), <anonymous>:4220:8)
    at callUpdatedHooks (eval at Kr (https://codesandbox.io/static/js/sandbox.03d74bce7.js:1:180898), <anonymous>:4348:7)
    at flushSchedulerQueue (eval at Kr (https://codesandbox.io/static/js/sandbox.03d74bce7.js:1:180898), <anonymous>:4333:3)
    at Array.eval (eval at Kr (https://codesandbox.io/static/js/sandbox.03d74bce7.js:1:180898), <anonymous>:1985:12)
    at flushCallbacks (eval at Kr (https://codesandbox.io/static/js/sandbox.03d74bce7.js:1:180898), <anonymous>:1911:14)

jan-demsar avatar Apr 10 '20 15:04 jan-demsar

Even if I call refetch method after variable has been changed, query won't load new results.

It only works if I call refetch(updatedVariables).

I have added 2 buttons under the input to test this as well.

Steps to reproduce:

  1. Change value of first input
  2. Press "Change value" button. That updates queryVariables that are being passed to the query
  3. Pressing "Refetch" button calls refetch method which does nothing
  4. Pressing "Refetch (pass variables)" button calls refetch(queryVariables) method which updates results (queryVariables is the same constant that has been passed to initial query.

Furthermore I noticed on the local development, that if I enable pooling, it will always fall back to primary variables. So even if I am able to get different results by calling refetch(queryVariables) the moment pool is triggered, variables seems to be reverted.

jan-demsar avatar Apr 10 '20 15:04 jan-demsar

Is there any update on this? I get the same error as @demisolutions whenever my reactive variables change.

kyosifov avatar Sep 01 '20 06:09 kyosifov

@Akryum

The problem seems to be this piece of code:

function baseRestart() {
        if (!started || restarting)
            return;
        restarting = true;
        vue_1.default.nextTick(function () {
            if (started) {
                stop();
                start();
            }
            restarting = false;
        });
    }

It seems that if baseRestart is executed a second time the vue_1 variable doesn't have the .default property instead it's the full Vue instance. If you remove .default then everything is working.

kyosifov avatar Sep 01 '20 06:09 kyosifov

@demisolutions It seems to be a problem when you use CDN mode of Vue js which makes it a global variable. In my project I was using Vue from vue/dist/vue.js which is the CDN version. Converted it to vue/dist/vue.esm.browser.jsin my webpack and worked.

Take note that If you include Vue in "Node" way like this const Vue = require('vue'); you will have to append the .default to the required, since now you will be using the new module system of ES6. Or you can just do import Vue from 'vue' and it will work fine.

kyosifov avatar Sep 08 '20 14:09 kyosifov

@Akryum thanks for the reply. I updated the codesandbox with your suggestion, but it is still the same.

Now I see the error:

[Vue warn]: Error in event handler for "hook:updated": "TypeError: Cannot read property 'nextTick' of undefined"

TypeError: Cannot read property 'nextTick' of undefined
    at baseRestart (https://yc7nf.csb.app/node_modules/@vue/apollo-composable/dist/useQuery.js:181:23)
    at restart (https://yc7nf.csb.app/node_modules/@vue/apollo-composable/dist/useQuery.js:213:9)
    at composition_api_1.watch.deep (https://yc7nf.csb.app/node_modules/@vue/apollo-composable/dist/useQuery.js:228:13)
    at applyCb (https://yc7nf.csb.app/node_modules/@vue/composition-api/dist/vue-composition-api.js:938:9)
    at Array.eval (https://yc7nf.csb.app/node_modules/@vue/composition-api/dist/vue-composition-api.js:897:20)
    at flushQueue (https://yc7nf.csb.app/node_modules/@vue/composition-api/dist/vue-composition-api.js:824:21)
    at VueComponent.flushPostQueue (https://yc7nf.csb.app/node_modules/@vue/composition-api/dist/vue-composition-api.js:790:5)
    at invokeWithErrorHandling (eval at Kr (https://codesandbox.io/static/js/sandbox.03d74bce7.js:1:180898), <anonymous>:1859:26)
    at VueComponent.Vue.$emit (eval at Kr (https://codesandbox.io/static/js/sandbox.03d74bce7.js:1:180898), <anonymous>:3885:9)
    at callHook (eval at Kr (https://codesandbox.io/static/js/sandbox.03d74bce7.js:1:180898), <anonymous>:4220:8)
    at callUpdatedHooks (eval at Kr (https://codesandbox.io/static/js/sandbox.03d74bce7.js:1:180898), <anonymous>:4348:7)
    at flushSchedulerQueue (eval at Kr (https://codesandbox.io/static/js/sandbox.03d74bce7.js:1:180898), <anonymous>:4333:3)
    at Array.eval (eval at Kr (https://codesandbox.io/static/js/sandbox.03d74bce7.js:1:180898), <anonymous>:1985:12)
    at flushCallbacks (eval at Kr (https://codesandbox.io/static/js/sandbox.03d74bce7.js:1:180898), <anonymous>:1911:14)

I am seeing this error, but only when running Jest tests. I don't think @kyosifov's solution will work in this case, as we are using vue-test-utils createLocalVue and not importing Vue anywhere.

We are using mock request handlers in our Jest tests to resolve mock data similar to how @NataliaTepluhina presents it in her Vue Apollo 2020 Testing Guide. However, whenever we update a reactive variable (whether a ref or reactive object), we get the same error as quoted above.

EDIT: A temporary fix for this when using localVue in Jest

  const localVue = createLocalVue();

  // Fix for @vue/apollo-composable in jest environment.
  Vue.default.nextTick = localVue.nextTick;

Mando75 avatar Oct 05 '20 17:10 Mando75

@Mando75 You are absolutely amazing 💯 💯 We are moving to a similar setup. I came up against this error when transitioning from mocking module imports that wrap individual queries to mocking Apollo query responses with mock-apollo-client. Can confirm that the temporary fix as shown above works!

JuroOravec avatar Nov 20 '20 09:11 JuroOravec

The issue with Cannot read property 'nextTick' of undefined has been resolved for me. However, I still experience that, when unit testing, then sometimes the queries are not re-triggered when having reactive variables.

I'm unable to pinpoint exactly when this happens, but one of the cases when this happens is when the reactive variables are computed (from @vue/composition-api) values. When using refs, and re-assigning new values inside watch, then it works.

Example:

This does not work:

const queryVariables = computed(() => ({
  var: someRef.value,
}));

const queryOptions = computed(() => ({
  enabled: someRef.value !== undefined,
  fetchPolicy: 'cache-first',
}));

const { result, loading } = useQuery(
  QUERY,
  queryVariables,
  queryOptions,
);

This works:

const queryVariables = ref({});
const queryOptions = ref({});

watch(someRef, (newValue) => {
  queryVariables.value = {
    var: newValue,
  };

  queryOptions.value = {
    enabled: newValue !== undefined,
    fetchPolicy: 'cache-first',
  };
});

const { result, loading } = useQuery(
  QUERY,
  queryVariables,
  queryOptions,
);

JuroOravec avatar Nov 23 '20 13:11 JuroOravec

i have the same issue.

  1. receiving date as Prop from parent component,
  2. defining query variables as ref with initial value
  3. watching prop update and updating variables inside watch block
  4. query ie expected to re-fetched as described in Docs. But it doesn't
  5. Tried to achieve re-fetch using reactive object, passing variables for query as props as well, but there was no way to solve this
<script lang="ts">

    export default defineComponent({
        name: 'ImagesList',
        props: {
            calendarDate: {
                type: String,
                required: true
            }
        },
        setup(props) {
          const query....(something)
          const {calendarDate} = toRefs(props)
          
          const variables = ref({
              date: new Date().toISOString()
          })

          watch(calendarDate, (newValue : string) : void => {
           variables.value = {
                date: new Date(newValue).toISOString()
            }
          })

          const {result, loading, error} = useQuery(query, variables)

          const expectedResults = useResult(result, null)
        
          return {timecardsForDay, loading, error, IMAGE_URL_PATH}
        }
    })
</script>

package.json "@apollo/client": "^3.3.9", "@quasar/extras": "^1.0.0", "@vue/apollo-composable": "^4.0.0-alpha.12", "@vue/composition-api": "^0.6.4", "apollo-cache-inmemory": "^1.6.6", "apollo-client": "^2.6.10", "apollo-link": "^1.2.14", "apollo-link-http": "^1.5.17", "axios": "^0.18.1", "core-js": "^3.6.5", "graphql": "^15.5.0", "graphql-tag": "^2.11.0", "node-fetch": "^2.6.1", "quasar": "^1.0.0", "vue-apollo": "^3.0.7", "vue-class-component": "^7.2.6", "vue-fragment": "^1.5.1", "vue-i18n": "^8.0.0", "vue-property-decorator": "^9.1.2", "vuex-typex": "3.1.6"

vitalykhe avatar Feb 24 '21 19:02 vitalykhe

I also have this problem

"@apollo/client": "^3.5.10", "@vue/apollo-composable": "^4.0.0-alpha.16",

reaink avatar Feb 28 '22 11:02 reaink

I also have this problem.

"@apollo/client": "^3.7.15", "@vue/apollo-composable": "^4.0.0-beta.7",

nikzanda avatar Jul 05 '23 16:07 nikzanda