nuxt-modules / apollo

Nuxt.js module to use Vue-Apollo. The Apollo integration for GraphQL.
https://apollo.nuxtjs.org
MIT License
956 stars 198 forks source link

Not reactive input data #539

Closed ulysse-lacour closed 8 months ago

ulysse-lacour commented 1 year ago

Environment

Operating System: Darwin

Describe the bug

I'm trying to create a search form (data in Strai backend, fetch via Graphql query) but using refresh method is using some sort of frozen query variable that is not updating, every request is send with variables to ''.

<script lang="ts" setup>
import { SEARCH_BLOGPOST_BY_TITLE } from "~/gql/SearchBlogPosts";
import type { BlogPostsType } from "~/types/BlogPosts";

const searchText = ref("");
const queryVariables = ref({
  Title: searchText.value,
});
const searchedData = ref<BlogPostsType>({ blogPosts: null });
let isLoading = ref(false);

const {
  data,
  error,
  refresh: search,
} = await useAsyncQuery<BlogPostsType>(
  SEARCH_BLOGPOST_BY_TITLE,
  queryVariables.value
);

const submitForm = async () => {
  isLoading.value = true;

  try {
    search();
  } catch (error) {
    console.log({ error });
  }

  searchedData.value.blogPosts = data?.value.blogPosts;

  // Reset loading state
  isLoading.value = false;
};

</script>

What I'm doing wrong ?

Expected behaviour

Expecting useAsyncQuery variables to update on each refresh call

Reproduction

No response

Additional context

No response

Logs

No response

premier213 commented 1 year ago

this is async query for use interaction use, useQuery

Screenshot_20230825_161251_Chrome

ulysse-lacour commented 1 year ago

@premier213 thank you for your help, unfortunatly couldn't make it to work with not async query for some reasons that aree beyond my comprehension....

BUT (inspired by this tutorial) I managed to have a very good result with this code :

<template>
  <div class="p-8">
    <h1 class="font-bold text-2xl mb-8">Search form</h1>
    <!-- Search input, every update of input query database -->
    <input
      type="text"
      v-model="searchText"
      name="Search"
      id="Search"
      class="border border-gray-600 rounded py-2 px-4 mr-2"
      placeholder="Search by name"
      @input="debouncedSubmitForm"
    />

    <!-- Error message -->
    <div v-if="errorMessage">{{ errorMessage }}</div>

    <!-- loading state -->
    <div v-else-if="isLoading">Loading..</div>

    <!-- Search results -->
    <div v-else-if="searchedData?.blogPosts?.data.length" class="mb-8">
      <p class="font-bold mb-2">Your search results:</p>
      <div class="flex flex-wrap">
        <div class="mr-4 mb-2 flex">
          {{ searchedData?.blogPosts }}
        </div>
      </div>

      <!-- Pagination -->
      <button v-if="currentPage > 1" @click="previousPage">PREVIOUS</button>
      <button v-if="currentPage < lastPage" @click="nextPage">NEXT</button>
    </div>

    <!-- Nothing found -->
    <p class="font-bold" v-else>No results found.</p>
  </div>
</template>

<script lang="ts" setup>
// Custom debounce function
import debounce from "@/assets/js/debounce";

// Graphql query
import { SEARCH_BLOGPOST_BY_TITLE } from "@/gql/SearchBlogPosts";

// Types
import type { BlogPostsType } from "@/types/BlogPosts";

// i18n / Language
const { locale } = useI18n();

// Search objects
const searchText = ref("");
const searchedData = ref<BlogPostsType>({ blogPosts: null });
const isLoading = ref(false);
const errorMessage = ref("");

// Pagination objects
const currentPage = ref(1);
const pageSize = ref(1); // number of item per page
const lastPage = ref(1); // stores amount of page in serach result

// Pagination functions
const previousPage = () => {
  // Decrement current page number
  currentPage.value--;
  // Search
  submitForm();
};

const nextPage = () => {
  // Increment current page number
  currentPage.value++;
  // Search
  submitForm();
};

// Search function
const submitForm = async () => {
  // Init loading state
  isLoading.value = true;

  // Query logic
  const { data, error } = await useAsyncQuery<BlogPostsType>(
    SEARCH_BLOGPOST_BY_TITLE,
    {
      Title: searchText.value,
      page: currentPage.value,
      pageSize: pageSize.value,
      locale: locale.value,
    }
  );

  // Watch for error
  if (error.value?.message) {
    errorMessage.value = error.value?.message;
  }
  // Handle search result
  else if (data?.value.blogPosts) {
    // Update displayed data based on query results
    searchedData.value.blogPosts = data?.value.blogPosts;

    // Update lastPage value with returned pageCount
    lastPage.value = data?.value.blogPosts?.meta.pagination.pageCount;
  }

  // Reset loading state
  isLoading.value = false;
};

// Debounce submit function to limit request frequency
const debouncedSubmitForm = debounce(submitForm, 500);

// Watch for locale changes to apply on search
watch(
  () => locale.value,
  async () => {
    // Reset search parameters
    currentPage.value = 1;
    pageSize.value = 1;
    lastPage.value = 1;

    // Resend search
    await submitForm();
  }
);
</script>

Hope some more senior could give feedback and provide better practices on this way of doing the search, and if done well that it could help some other bumping their heads against wall like I did !