0

I just got into custom hooks and i created a custom hook that fetches data from an API.

interface DataProps<Type> {
  results: Type[];
  isLoading: boolean;
  LIMIT: number;
  offset: number;
}

interface Pokemon {
  name: string;
  url: string;
}

const useGetData = (url: string) => {
  const [data, setData] = useState<DataProps<Pokemon>>({
    results: [],
    isLoading: true,
    LIMIT: 80,
    offset: 0
  });

  const fetchData = async () => {
    const res = await fetch(
      url +
        new URLSearchParams({
          limit: data.LIMIT + "",
          offset: data.offset + ""
        })
    );
    const { results } = await res.json();
    setData((prevValue) => ({
      ...prevValue,
      results: [...prevValue.results, ...results],
      isLoading: false,
      offset: prevValue.offset + prevValue.LIMIT
    }));
  };

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

  return data;
};

In my App component, I use it like this:

export default function App() {
  let data = useGetData(
    `https://pokeapi.co/api/v2/pokemon?`
  );

  return (
    <div className="App">
      {data.isLoading && <div>Loading...</div>}
      <ul>
        {data.results.map((pokemon) => (
          <li key={pokemon.name}>{pokemon.name}</li>
        ))}
      </ul>
    </div>
  );
}

Works great, but this is only for displaying purposes. I would like, for example, to remove an element from the results array. How would I achieve that since I don't have a setData() to do that? From what I know, mutating state without a set...() is bad when you want the change in state to generate a rerender (like in my case, where I want the delete operation to remove the selected element from screen).

yeahman14
  • 75
  • 1
  • 6

1 Answers1

1

In your hook instead of return data use return [data, setData]

Then in your component instead of

let data = useGetData('https://pokeapi.co/api/v2/pokemon?');

do

const [data, setData] = useGetData('https://pokeapi.co/api/v2/pokemon?');

You now have access to your setter in the component and can manipulate the state.

  • Thank you very much! May I ask why is typescript not inferencing the types correctly? When I use useGetData in App it shows that data is "DataProps | React.Dispatch>>". Same goes for setData. – yeahman14 Apr 03 '22 at 11:31