#useFetcher

1 messages · Page 1 of 1 (latest)

plain grail
#

Hi there! I'm working on my first and easy Remix project and now I'm trying to make a button that allows users to fetch 8 random countries from an url. I'm already fetching the countries in the index, use the data in a component(CountriesGrid) and now I'm trying to build that feature. I thought useFetcher would be the best choice since I don't wanna navigate away from the page, but I'm not sure if I used it correctly. Right now, when I click on the button it looks like the fetch is correct but it doesn't display anything and it gives me this error: Error: You made a GET request to "/react_devtools_backend_compact.js.map" but did not provide a loader for route "routes/_layout.$cca2", so there is no way to handle the request.

https://github.com/EduardD22/rest-countries-api-remix

cloud peak
#

Use the loader and useLoaderData to fetch and load data instead

plain grail
cloud peak
#

Check your _layout.$cca2 route file

safe onyx
# plain grail I’m already using the loader and useLoaderData to fetch all the countries

So looking at the repo you gave I believe you are using fetcher incorrect. The fetcher args for submit in particular accept either an object, an event that has an HTML form associated with it, or a FormData object. You also need to specify a formAction in the case that you aren’t submitting from an existing form. (Which in your case you aren’t)

I also don’t believe you are supposed to use a fetcher to directly fetch from an external api like that. I believe the remix approach would be to take the logic you have in your fetchRandomCountries function and move it to the server and have a loader call that function and return the results. Then you’d point your fetcher at that loader to receive the data and you’d just use ‘fetcher.load(“/api/getCountries”)

plain grail
charred basalt
charred basalt
#

I think this part is the key. Use route loader data for initial data, then fetcher for new data.

  const loaderData = useLoaderData<typeof loader>();
  const fetcher = useFetcher<typeof loader>();

  // loader data will have initial countries
  // fetcher.data will have new countries
  const countries = fetcher.data?.countries ?? loaderData.countries;

  const getRandomCountries = () => fetcher.load("/resource/countries");
plain grail
# charred basalt I think this part is the key. Use route loader data for initial data, then fetch...

so help me understand if this is how it works please haha:

  1. when my route renders, the loader function fetches an initial set of countries
  2. CountriesGrid uses useLoaderData to get and display them
  3. the button calls getRandomCountries and it triggers fetcher.load which basically re-executes the loader function (the one in the index route? it's fetcher.load("/?index") in the link that you sent) and gets a new set of countries.
  4. while the refetch happens the component still shows the old data, when fetcher.data updates the component renders with the new data
charred basalt
#

Yes, except in #3, I fixed it to fetcher.load("/resource/countries") (i missed it during the refactor to resource routes)

charred basalt
#

As you can see, it really cleaned up the <CountriesGrid> component... the first part is what data to render... and the rest just renders that data (regardless of how it got there)... no separate paths between initial loader data and fetcher data

plain grail