Komunikacja z API w React.js

Ten wpis jest 19 częścią z 41 w kursie React.js
wp-content/uploads/2017/10/React_logo_wordmark-300x101-1-e1508612391308.png
  1. React.js: Wprowadzenie do kursu od podstaw
  2. Poznaj React.js
  3. Pierwszy komponent w React.js
  4. Props czyli atrybuty w React.js
  5. Podział na komponenty w React.js
  6. Klasy jako komponenty React.js
  7. Interakcja z komponentami React.js
  8. Stan komponentów React.js
  9. State w React.js 2
  10. Metody cyklu życia komponentu w React.js
  11. React.js w przykładach: filtrowanie statycznej listy
  12. Tworzenie aplikacji React.js dzięki create-react-app
  13. React.js na GitHub Pages dzięki create-react-app
  14. Testowanie aplikacji React.js — podstawy Enzyme
  15. Testowanie React.js w Enzyme — props, state i interakcje
  16. Poprawne bindowanie funkcji w React.js
  17. Odpowiadam na pytania: Babel, ECMAScript, destrukturyzacja, onClick, className
  18. Komunikacja pomiędzy komponentami w React.js
  19. Komunikacja z API w React.js
  20. Formularze w React.js — kontrolowane komponenty
  21. Formularze w React.js — niekontrolowane komponenty
  22. Odpowiadam na pytania: props, nawiasy klamrowe, funkcje vs klasy, import react
  23. TDD w React.js z pomocą react-testing-library
  24. Flux i Redux: globalny store i jednokierunkowy przepływ danych
  25. React + Redux — kurs: wprowadzenie i podstawy
  26. React + Redux — filtrowanie listy, proste selektory
  27. Projektowanie komponentów: Presentational & Container Components
  28. Asynchroniczność w Redux: redux-thunk
  29. Kiedy używać state, a kiedy Redux?
  30. Nowe metody cyklu życia: getDerivedStateFromProps i getSnapshotBeforeUpdate
  31. Leniwe ładowanie komponentów w React dzięki import
  32. Higher Order Reducers — Redux i powtarzanie kodu
  33. React Hooks — wprowadzenie i motywacja
  34. React Hooks: useState, czyli stan w komponentach funkcyjnych
  35. React Hooks: useState — wiele stanów, callbacki i inne niuanse
  36. React Hooks: useEffect — efekty uboczne w komponencie
  37. React Hooks a żądania do API
  38. useReducer — przenoszenie logiki poza komponent
  39. useMemo, useCallback, czyli rozwiązanie problemów ze zmieniającymi się propsami
  40. Wady React Hooks
  41. React Hooks: Piszemy własne hooki!

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 🙂

Możemy Cię nauczyć tego wszystkiego szybciej: Naucz się React na szkoleniu Type of Web!

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.

Nie wysyłamy spamu, tylko wartościowe informacje. W każdej chwili możesz się wypisać klikając „wypisz się” w stopce maila.

Ć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).

Nawigacja po kursie:
  1. React.js: Wprowadzenie do kursu od podstaw
  2. Poznaj React.js
  3. Pierwszy komponent w React.js
  4. Props czyli atrybuty w React.js
  5. Podział na komponenty w React.js
  6. Klasy jako komponenty React.js
  7. Interakcja z komponentami React.js
  8. Stan komponentów React.js
  9. State w React.js 2
  10. Metody cyklu życia komponentu w React.js
  11. React.js w przykładach: filtrowanie statycznej listy
  12. Tworzenie aplikacji React.js dzięki create-react-app
  13. React.js na GitHub Pages dzięki create-react-app
  14. Testowanie aplikacji React.js — podstawy Enzyme
  15. Testowanie React.js w Enzyme — props, state i interakcje
  16. Poprawne bindowanie funkcji w React.js
  17. Odpowiadam na pytania: Babel, ECMAScript, destrukturyzacja, onClick, className
  18. Komunikacja pomiędzy komponentami w React.js
  19. Komunikacja z API w React.js
  20. Formularze w React.js — kontrolowane komponenty
  21. Formularze w React.js — niekontrolowane komponenty
  22. Odpowiadam na pytania: props, nawiasy klamrowe, funkcje vs klasy, import react
  23. TDD w React.js z pomocą react-testing-library
  24. Flux i Redux: globalny store i jednokierunkowy przepływ danych
  25. React + Redux — kurs: wprowadzenie i podstawy
  26. React + Redux — filtrowanie listy, proste selektory
  27. Projektowanie komponentów: Presentational & Container Components
  28. Asynchroniczność w Redux: redux-thunk
  29. Kiedy używać state, a kiedy Redux?
  30. Nowe metody cyklu życia: getDerivedStateFromProps i getSnapshotBeforeUpdate
  31. Leniwe ładowanie komponentów w React dzięki import
  32. Higher Order Reducers — Redux i powtarzanie kodu
  33. React Hooks — wprowadzenie i motywacja
  34. React Hooks: useState, czyli stan w komponentach funkcyjnych
  35. React Hooks: useState — wiele stanów, callbacki i inne niuanse
  36. React Hooks: useEffect — efekty uboczne w komponencie
  37. React Hooks a żądania do API
  38. useReducer — przenoszenie logiki poza komponent
  39. useMemo, useCallback, czyli rozwiązanie problemów ze zmieniającymi się propsami
  40. Wady React Hooks
  41. React Hooks: Piszemy własne hooki!

Nie wysyłamy spamu, tylko wartościowe informacje. W każdej chwili możesz się wypisać klikając „wypisz się” w stopce maila.

Subscribe
Powiadom o
guest
19 komentarzy
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
Michal Jaracz
Michal Jaracz
2 lat temu

Mam problem z zapisaniem danych w state po pobraniu fetch’em, możliwe, że dane w ogóle się nie pobierają z zewnętrznego API

Zamieszczam kod, jakieś pomysły? 🙂

https://github.com/mjaracz/ReactFetch

Michal Jaracz
Michal Jaracz
2 lat temu
Reply to  Michal Jaracz

Cześć Michał!
Przesłałem na githuba, teraz widać dobrze cała strukturę, masz jakiś pomysł czemu, items zwraca null

Michal Jaracz
Michal Jaracz
2 lat temu

nie działa na codepenie, ponieważ skopiowałem każdy komponent do jednego skryptu. każdy komponent taki jak

był zapisany w osobnym pliku i imporotwany do app.js, zrobiłem tak bo nie chciało mi sie kopiować każdgo komponentu do osobnego codepena

za chwile psrawdze to literowke

trackback

[…] Komunikacja z API w React.js […]

Łukasz
Łukasz
1 rok temu

Witam, trafiłem tutaj na „schody”. Wszystko działa ładnie, ale gdy próbuję dać do fetch’a zamiast adresu do generowania jsona dać swojego z dysku wyskakuje mi:

Unhandled Rejection (SyntaxError): Unexpected token < in JSON at position 0 Próbowałem różnych jsonów, nawet pobrałem jeden z wygenerowanych jsonów, i ciągle to samo. Czy importowanie z dysku się czymś różni ? Pozdrawiam

Łukasz
Łukasz
2 lat temu
Reply to  Łukasz

EDIT: Poradziłem sobie, rozwiązanie było banalne (o ile dobre) usunąłem całkiem fetcha z componentDidMount i po prostu dodałem this.setState i przypisałem zaimportowany JSON. działa 🙂

Kamil
Kamil
1 rok temu

Cześć,

Mam takie pytanie, ponieważ szukam po różnych forach i nie mogę znaleźć działającej odpowiedzi.
W jaki sposób można wywołać funkcję w stylu onInit lub $(document).ready w React?
Chodzi o sytuację, gdzie w ComponentDidMount używam fetch aby pobrać dane z api i wyświetlić je na stronie i potem automatycznie zaraz po ich załadowaniu wykonać akcję np. zablokowania/odblokowania buttonów na podstawie danych z poszczególnych pól wyświetlanych na ekranie.
W każdy jeden sposób w jaki próbuję to zrobić najpierw wywoływana jest funkcja a dopiero potem dane są renderowane na stronie, więc wszystkie argumenty jakie są brane pod uwagę w tym czasie są jeszcze nullem.

przykład funkcji:
componentDidMount(){
fetch(….); // tutaj działa wszystko poprawnie
prepareButtons();
}

prepareButtons(){
if(this.state.myObject.name == null){
alert(this.state.myObject.name); // tutaj dla sprawdzenia jaka wartośc wchodzi w sprawdzenie ifa -> zawsze pokazuje null
document.getElementById(„changeNameButton”).setAttribute(„disabled”, „true”);
}
}

W sytuacji kiedy nawet wartość nie jest nullem (co widać w konsoli i na stronie po załadowaniu) funkcja widzi ją jako null ponieważ zawsze wykonuje się ona zanim wszystkie pola zostaną uzupełnione.

Dziękuję
Pozdrawiam

obserwujewnioskuje
obserwujewnioskuje
1 rok temu

Cześć Michał.
Można ten guzik zrobić w ten sposób?

Joanna Trapp
Joanna Trapp
1 rok temu

Hej, mam problem z zastosowaniem powyższego przykładu w mojej aplikacji. Otóż moje API zwraca mi taki obiekt:
{
„NumberOfPln”: 366814918.794,
„NumberOfBtc”: 1900.00208,
„NumberOfBcc”: 109.17164,
„NumberOfEth”: 0,
„NumberOfLtc”: 0.41808
}
Jest to API udostępnione przez localhost, taki wynik otrzymuję po wpisaniu zapytania (http://localhost:9000/api/transactions/account?id=1) typu get w Postman.

Piszę więc w React:
class App extends Component {
state = {
status: []
};
componentDidMount = () => {
fetch(„http://localhost:9000/api/transactions/account?id=1”)
.then(res => res.json())
.then(json => this.setState({
status: json.results
}));
}
render() {
console.log(this.state.status);
return(

{this.state.status}

)
}
}
export default App;

Otrzymuję w console log undefined…. Co robię źle? I jak tutaj „wyciągnąć potem pojedyncze wartości, czy wystarczy np. status.NumberOfPln?

Joanna Trapp
Joanna Trapp
1 rok temu

Wielkie dzięki Michał. Sama siedziałam nad tym cały wieczór i nie widziałam!

trackback

[…] Komunikacja z API w React.js […]

Kopek
Kopek
1 rok temu

Mógłbyś wstawić gdzieś przykład z tym ćwiczeniem eventemitter?

Pozdrawiam 😉

Kopek
Kopek
1 rok temu

Możesz gdzieś wstawić przykład ćwiczenia z eventemitter?