Home > OS >  Need router.query variable passed to API URL call, but is undefined on first render
Need router.query variable passed to API URL call, but is undefined on first render

Time:08-01

I have the following API Call:

const router = useRouter();
const { albumQuery } = router.query;
const [albums, setAlbums] = useState([]);

const fetchAlbumsHandler = useCallback(async () => {
    setIsLoading(true);
    setError(null);
    try {
      const url = `http://ws.audioscrobbler.com/2.0/?method=album.search&album=${albumQuery}&api_key=MY_API_KEY&format=json`;
      const res = await fetch(url);
      const data = await res.json();

      if (!res.ok) {
        throw new Error("Something went wrong!");
      }

      const jsonAlbums = data.map(
      // JSON business Logic
      );

      setAlbums(transformedAlbums);
    } catch (error) {
      setError(error.message);
    }
    setIsLoading(false);
  }, []);

With the corresponding useEffect function:

useEffect(() => {
      fetchAlbumsHandler();
  }, [fetchAlbumsHandler]);

However, the API call takes ${albumQuery} as undefined on the first render due to NextJS implementation details. Is there a way for me to access the variable on the first render?

CodePudding user response:

No, if the albumQuery isn't available on the initial render then the code should handle waiting for it to become available.

The existing code is assuming albumQuery is available on the initial render and attempts to close it over in the useCallback hook. After this the useEffect hook is called and since fetchAlbumsHandler is now a stable reference the useEffect hook won't be retriggered nor will fetchAlbumsHandler be re-memoized since the useCallback hook has an empty dependency array.

Minimally albumQuery appears to be a dependency for the useCallback hook and/or the useEffect hook. If fetchAlbumsHandler isn't passed as a prop to children there's no real benefit to memoizing it. I suggest moving it into the useEffect hook callback and using albumQuery as a dependency.

Example:

const router = useRouter();
const { albumQuery } = router.query;
const [albums, setAlbums] = useState([]);

useEffect(() => {
  const fetchAlbumsHandler = async () => {
    setIsLoading(true);
    setError(null);

    try {
      const url = `http://ws.audioscrobbler.com/2.0/?method=album.search&album=${albumQuery}&api_key=MY_API_KEY&format=json`;
      const res = await fetch(url);
      const data = await res.json();

      if (!res.ok) {
        throw new Error("Something went wrong!");
      }

      const jsonAlbums = data.map(
      // JSON business Logic
      );

      setAlbums(transformedAlbums);
    } catch (error) {
      setError(error.message);
    }
    setIsLoading(false);
  }

  fetchAlbumsHandler();
}, [albumQuery]);
  • Related