2

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

4
  • 1
    Hi @pcpbiscuit , could you provide some code to see your solution approach? Commented Jul 11, 2023 at 11:36
  • @Klian I've added some code as you asked Commented Jul 11, 2023 at 11:56
  • Can you post your code using codesandbox.io/dashboard? Commented Jul 11, 2023 at 12:15
  • @LinDu It's going to take some time to recreate all this logic in codesandbox. Maybe I can clarify something in the code I provided? Commented Jul 11, 2023 at 13:02

1 Answer 1

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>
<...>
)
  
Sign up to request clarification or add additional context in comments.

1 Comment

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.