Aven
Intro to React Native »

Chapter 6: React Native API Fetch

New Custom Hook

From the home screen, lets create a new hook file to load cities:

HomeScreen.js
import { useCitySearch } from "./Cities";
// ...
function CitiesList({ filter }) {
  const cities = useCitySearch(filter);
  if (!cities) {
    return null;
  }
  return cities.map((city) => <CityRow city={city} key={city.cityId} />);
}
Cities.js
const EXAMPLE_CITIES = [
  {
    cityId: 5368361,
    name: "Los Angeles",
    country: "US",
  },
  {
    cityId: 2643743,
    name: "London",
    country: "GB",
  },
  {
    cityId: 1273294,
    name: "Delhi",
    country: "IN",
  },
];

export function useCitySearch(filter) {
  const cities = filter
    ? EXAMPLE_CITIES.filter((c) => c.name.match(filter))
    : EXAMPLE_CITIES;
  return cities;
}

Do something when filter changes:

CitySearch.js
import { useEffect, useState, useRef } from "react";

export function useCitySearch(filter) {
  const timeout = useRef(null);
  useEffect(() => {
    alert('Search for: '+trimmedFilter);
  }, [trimmedFilter]);
  return [];
}

Hook debounce

We can use a timeout and useRef to make the effect happen less often:

CitySearch.js
import { useEffect, useRef } from "react";

export function useCitySearch(filter) {
  const trimmedFilter = filter.trim();
  const timeout = useRef(null);
  useEffect(() => {
    if (filter.length < 3) {
      return;
    }
    clearTimeout(timeout.current)
    timeout.current = setTimeout(() => {
      alert('Search for: '+trimmedFilter);
    }, 200);
  }, [trimmedFilter]);
  return [];
}

Fetch API

React native supports the fetch function that you find in web browsers.

fetch(`https://aven.io/api/cities?name=${trimmedFilter}`)
  .then((res) => res.json())
  .then((results) => {
    setCities(results.cities);
  })
  .catch((err) => {});

Bring it all together

We can also use a ref to store a timeout, allowing us to debounce the queries:

Cities.js
import { useEffect, useState, useRef } from "react";

export function useCitySearch(filter) {
  const trimmedFilter = filter.trim();
  const [cities, setCities] = useState(null);
  const timeout = useRef(null);
  useEffect(() => {
    if (filter.length < 3) {
      return;
    }
    clearTimeout(timeout.current)
    timeout.current = setTimeout(() => {
      fetch(`https://aven.io/api/cities?name=${trimmedFilter}`)
        .then((res) => res.json())
        .then((results) => {
          setCities(results.cities);
        })
        .catch((err) => {});
    }, 150)
  }, [trimmedFilter]);

  return cities;
}

Shortcomings

This simple approach works, but there are some caveats:

  • The city list will never re-load
  • Other components will fetch seperately rather than sharing data
  • The cache behavior should apply local filter
  • We should show a loading indicator
  • Errors should be displayed to the user

In the next section we will discuss saving your data in a memory store, to help with some of these issues.

Next: Stores

© Aven LLC and Aven Contributors. Licensed under Creative Commons BY-NC-SA 4.0

Open Source under Apache 2.0