4

I'm a little bit confused about using useEffect,useCallback and running RTK Queries. What I'm trying to achieve is users would be able to search movies based on an input field provided in the app.

There is a Home Page with an input field for users to search for movies. also, I have a useSearchMovieQuery in RTK Query API which search for whatever user enters in the search field. I want to prevent the query from running on the initial render, which can be achieved by skipping the query using "skip" or "skipToken".

I want only to run this query after the user stops typing, not immediately after onChange event in the search field.

here is what I've tried so far.

const Home = () => {
  const [page, setPage] = useState<number>(1);
  const [skip, setSkip] = useState<boolean>(true);
  const [searchQuery, setSearchQuery] = useState<string>("");
  const { data: popularMovies, isLoading: popularLoading } =
    useGetPopularMoviesQuery(page);
  const { data: topRatedMovies, isLoading: topRatedLoading } =
    useGetTopRatedMoviesQuery();
  const { data: upcomingMovies, isLoading: upcomingLoading } =
    useGetUpcomingMoviesQuery();
  const {
    data: searchResult,
    isSuccess: searchedForMovie,
    isFetching,
    isError,
  } = useSearchMovieQuery(searchQuery, { skip });
  const handleOnChangePage = (e: unknown, value: number) => {
    setPage(value);
  };
  const handleSearch = (
    event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
  ) => {
    setSearchQuery(event.currentTarget.value);
    setSkip((prev) => !prev);
  };

  return (
    <>
      <div className="category-box container">
        <div className="section mb-3">
          <FormControl fullWidth sx={{ m: 1 }}>
            <OutlinedInput
              id="outlined-adornment-amount"
              placeholder="Search Movies..."
              value={searchQuery}
              onChange={handleSearch}
            />
          </FormControl>
          {searchedForMovie && (
            <SearchResult>
              <MoviesList moviesType={searchResult.results} />
            </SearchResult>
          )}
</>

the confusing thing is that I want to set skip to true for starting the query search, and also only run this after user stops typing. maybe using setTimeout?

the state I'm using for skip query is:

const [skip, setSkip] = useState<boolean>(true);

the state I'm using for user search query is:

  const [searchQuery, setSearchQuery] = useState<string>("");

and the handleSearch function which runs onChange event for the input is:

      const handleSearch = (
    event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
  ) => {
    setSearchQuery(event.currentTarget.value);
    setSkip((prev) => !prev);
  };

that setSkip in the handle search function is one of the problems I know so far that shouldn't be there :D

any helps?

Naderjlyr
  • 165
  • 4
  • 13

1 Answers1

4

I would use something like useDebounce

const [searchQuery, setSearchQuery] = useState<string>("");
const debouncedSearchQuery = useDebounce(searchQuery, 500);
  const {
    data: searchResult,
    isSuccess: searchedForMovie,
    isFetching,
    isError,
  } = useSearchMovieQuery(debouncedSearchQuery, { skip: debouncedSearchQuery == "" });

This way you will only search when the searchQuery has not changed in the last 500ms and when it is not the empty string.

phry
  • 35,762
  • 5
  • 67
  • 81
  • thank you for your answer, I will give it a try and let you know the result. is it a react built-in hook? – Naderjlyr Jun 04 '22 at 20:49
  • I'm using typescript and it seems the type of debouncedSearchQuery is not string. it is [string,ControlFunction] so it cannot be sent to the rtk search query. updated: fixed by const [debouncedSearchQuery] = useDebounce(searchQuery, 500); – Naderjlyr Jun 04 '22 at 20:54
  • it seems working. about that setSkip function. is it ok to put it there? I mean for the performance issues I'm asking. – Naderjlyr Jun 04 '22 at 21:03
  • Well, your call would flip it on every keypress, so you would essentially search on every second key press. Not sure if thats really what you want. – phry Jun 04 '22 at 21:22
  • in your opinion, what is the proper way to implement the search? I mean, running the query when input lost focus? or after a short amount of time? or ... – Naderjlyr Jun 05 '22 at 09:31
  • I'd debounce by 500ms or so. You never know if they will ever unfocus. – phry Jun 05 '22 at 11:10