Komunikacja z API w React.js

Ten wpis jest 19 częścią z 32 w kursie React.js

Bardzo często powracającym wątkiem jest pytanie o to, w jaki sposób zaimplementować komunikację z API w React.js. Moja odpowiedź może Cię nieco zaskoczyć: React nie ma nic do tego. Możesz to robić absolutnie dowolnie.

Plan

Rozpatrzę teraz popularny przypadek: W momencie załadowania aplikacji, potrzebuję pobrać jakieś dane z API. Gdy już będą gotowe — chcę je wyświetlić. Brzmi dobrze? Rozbuduję więc swój poprzedni przykład: Znaną i lubianą listę kontaktów 😉

Wracam do kodu stąd:

Podział na komponenty w React.js

Gotowa implementacja z tej części kursu dostępna jest tutaj: github.com/mmiszy/typeofweb-kurs-react/tree/contacts-list-1

Przygotowanie

Nieco zmieniam tamten przykład. Przede wszystkim to komponent App będzie „dostarczycielem” danych do ContactsList. Przekaże tablicę jako props:

export const App = () => {
  return (
    <div>
      <AppHeader />
      <main className="ui main text container">
        <ContactsList contacts={[]} />
      </main>
    </div>
  );
}

Tę tablicę za moment wypełnię danymi z API. Przykładowy obiekt z API wygląda tak:

{
  "gender": "female",
  "name": { "title": "mrs", "first": "célia", "last": "lopez" },
  "location": {
    "street": "3403 rue paul-duvivier",
    "city": "dunkerque",
    "state": "var",
    "postcode": 52018
  },
  "email": "célia.lopez@example.com",
  "login": {
    "username": "purplelion429",
    "password": "spoiled",
    "salt": "nUY17qZz",
    "md5": "2660f36114ad97ebbb38729d1e1ad935",
    "sha1": "14e893bf4d76c2e6bc942846d557acc3c1fa3223",
    "sha256": "d032a528a2da82f5b9ef37d3c3277c9255fef5de73db1e979402c2ee86fe4cf2"
  },
  "dob": "1956-01-28 09:02:34",
  "registered": "2011-05-16 19:04:38",
  "phone": "04-98-07-66-00",
  "cell": "06-33-63-47-98",
  "id": { "name": "INSEE", "value": "256045054319 82" },
  "picture": {
    "large": "https://randomuser.me/api/portraits/women/80.jpg",
    "medium": "https://randomuser.me/api/portraits/med/women/80.jpg",
    "thumbnail": "https://randomuser.me/api/portraits/thumb/women/80.jpg"
  },
  "nat": "FR"
}

Ja chciałbym z tego wyciągnąć:

  • pełne imię i nazwisko
  • numer telefonu
  • link do avatara
  • coś unikalnego co posłuży za atrybut key (wymagany przy tablicach elementów)

Wymaga to tylko wyjęcia i połączenia niektórych pól:

const avatarUrl = contact.picture.thumbnail;
const { title, first, last } = contact.name;
const name = `${title} ${first} ${last}`.trim();
const phone = contact.phone;
const key = contact.login.username;

Ostatecznie cały komponent:

export class ContactsList extends React.Component {
  contactToContactItem = contact => {
    const avatarUrl = contact.picture.thumbnail;
    const { title, first, last } = contact.name;
    const name = `${title} ${first} ${last}`.trim();
    const phone = contact.phone;
    return <ContactItem key={key} avatarUrl={avatarUrl} name={name} phone={phone} />;
  };

  render() {
    return (
      <ul className="ui relaxed divided list selection">
        {this.props.contacts.map(this.contactToContactItem)}
      </ul>
    );
  }
}

Nic nadzwyczajnego, to wszystko już na pewno widziałaś/eś w poprzednich odcinkach kursu. Idźmy dalej… został tylko jeden komponent, który wyświetla podane informacje:

export const ContactItem = ({ avatarUrl, name, phone }) => {
  return (
    <li className="item">
      <img src={avatarUrl} className="ui mini rounded image" alt="" />
      <div className="content">
        <h4 className="header">{name}</h4>
        <div className="description">{phone}</div>
      </div>
    </li>
  );
};

Uff! To tyle jeśli chodzi o przygotowania.

Pobieranie danych z REST API w React.js

Do sedna! Chcę pobierać listę kontaktów z API randomuser.me. Potrzebne mi będzie jedno żądanie GET. Najprościej zrobić je przy pomocy fetch wbudowanego w przeglądarkę 🙂

Jak wspomniałem wcześniej, dobrym miejscem na wykonanie pytania do API jest funkcja componentDidMount(…). Tam też umieszczę swój kod. Wykonam żądanie, poczekam na odpowiedź, a wynik zapiszę w state. Następnie przekażę to do komponentu ContactsList:

export class App extends React.Component {
  state = {
    contacts: []
  };

  componentDidMount() {
    fetch("https://randomuser.me/api/?format=json&results=10")
      .then(res => res.json())
      .then(json => this.setState({ contacts: json.results }));
  }

  render() {
    return (
      <div>
        <AppHeader />
        <main className="ui main text container">
          <ContactsList contacts={this.state.contacts} />
        </main>
      </div>
    );
  }
}

Działa!

Spinner na czas ładowania…

No tak, działa, ale jednak efekt nie jest idealny. Początkowo renderuje się zupełnie pusta lista, a dopiero po chwili pojawiają się dane. Zmienię to. Chcę, aby na początku wyświetlał się napis Ładowanie…:

{contacts ? <ContactsList contacts={contacts} /> : 'Ładowanie…'}

Korzystam z faktu, że wyrażenia wewnątrz {} w JSX są wykonywane niemal jak zwykły JavaScript — i mogę tutaj użyć operatora trójoperandowego. W prawdziwej aplikacji zamiast napisu Ładowanie… prawdopodobnie chciałbym dodać jakiś spinner, który zamknąłbym np. w LoadingComponent 🙂

Podsumowanie

Poznałaś/eś właśnie podstawowy sposób pobierania i wyświetlania danych z REST API w React.js. To nie było takie trudne, prawda? Cały kod: github.com/mmiszy/typeofweb-kurs-react/tree/contacts-list-1

Jeśli chcesz na bieżąco dowiadywać się o kolejnych częściach kursu React.js to koniecznie śledź mnie na Facebooku i zapisz się na newsletter.

Ćwiczenie

Ćwiczenie: Dodaj do aplikacji guzik „odśwież”, który spowoduje ponowne pobranie i wyrenderowanie listy kontaktów (dane z randomuser.me są losowe, więc za każdym razem będą inne).