0

There is a search result page where query params are passed to useQuery. On this page, we can change our search prompt (query param essentially) however I only want to refetch when user click "Search" button.

I've tried setting enabled:false and refetch() on button click, however in this case I don't get data when page mounts. Is there any way to fetch data only once on mount and then manually refetch with new params? I had an idea of using refetch() in useEffect but it doesn't look like the right way to do it

Example code:

-model.ts

const useSearch = (params) => {

<some logic with params>

return useQuery<Type>(['/search' + params], {enabled: false})

-view.tsx

const {query, push} = useRouter()
const {data, refetch} = useSearch(query.search)
const handleSearchParams = (v) => {push({query: {search: v})}

return(
<...>
    <Input onChange={handleSearchParams} value={query.search} />
    <Button onClick={refetch}>Search</Button>
<...>
)

My final code looks like this:

const {query, push, isReady} = useRouter()
const [value, setValue] = useState(query.search);
const {data} = useSearch(query.search)

  useEffect(() => {
    if (!isReady) return;
    setValue(query.q);
  }, [isReady, query.q]);

  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
    setValue(e.target.value);
  };

  const handleUpdateSearchQuery = () => {
    push({ query: { ...query, q: value } });
  };

return(
<...>
    <Input onChange={handleChange} value={value} />
    <Button onClick={handleUpdateSearchQuery}>Search</Button>
<...>
)

Due to the nature of how nextJS router works (query params are undefined during the initial render), you still have to use useEffect in order to set initial value for your input from query params

PCPbiscuit
  • 417
  • 5
  • 16

2 Answers2

1

You don't need to control when react-query 're-fetches'. The component subscribes to the query you want to load by the query key (in your case the search string you pass to useSearch). What you should be doing instead is controlling when your query key is being changed. Then react-query will fetch and refetch whenever that state changes.

e.g.

const {query, push} = useRouter()
// use query.search as the initial value we query for
const [activeQuery, setActiveQuery] = useState(query.search);
// fetch the data for the active query
const {data} = useSearch(activeQuery)

// Updates the query.search when the input changes
const handleSearchParams = (v) => {push({query: {search: v})}

// Updates the active query to equal query.search 
const handleOnClick = () => { setActiveQuery(query.search) }

return(
<...>
    <Input onChange={handleSearchParams} value={query.search} />
    <Button onClick={handleOnClick}>Search</Button>
<...>
)
  
Chad S.
  • 6,252
  • 15
  • 25
  • Fair enough. I ended up with the same solution as you provided. However, NextJs router returns `query` as `undefined` during the initial render, so you have to still use `useEffect` hook in order to update `activeQuery` state. I will update my answer with fully working code tomorrow – PCPbiscuit Jul 12 '23 at 23:30
0

Setting enabled: false in the useQuery options, the initial data fetching is disabled. This allows you to manually trigger the fetch when needed. Add a useEffect hook to refetch the data when the search param changes

useEffect(() => {
  refetch();
}, [query.search])

the data will be fetched once on mount and then refetched whenever the search param changes due to the useEffect hook.

Nazrul Chowdhury
  • 1,483
  • 1
  • 5
  • 11
  • If you read my post carefully, you may notice that I've mentioned useEffect approach but it doesn't seem like the best solution in this case. – PCPbiscuit Jul 11 '23 at 18:57
  • hmm.. i see. Do give us an update if you have manage to pull it off some other way. I surely can't think of a better approach. I am interested in finding out. – Nazrul Chowdhury Jul 11 '23 at 19:07
  • Yeah, definitely. I'm trying different approaches right now – PCPbiscuit Jul 11 '23 at 19:09