Niedawno przeniosłem się z Angular do ReactJs. Używam jQuery do wywołań API. Mam API, które zwraca losową listę użytkowników, która ma zostać wydrukowana na liście.
Nie wiem, jak pisać wywołania interfejsu API. Jaka jest najlepsza praktyka w tym zakresie?
Próbowałem wykonać następujące czynności, ale nie otrzymuję żadnych wyników. Jestem otwarty na wdrażanie alternatywnych bibliotek API w razie potrzeby.
Poniżej mój kod:
import React from 'react';
export default class UserList extends React.Component {
constructor(props) {
super(props);
this.state = {
person: []
};
}
UserList(){
return $.getJSON('https://randomuser.me/api/')
.then(function(data) {
return data.results;
});
}
render() {
this.UserList().then(function(res){
this.state = {person: res};
});
return (
<div id="layout-content" className="layout-content-wrapper">
<div className="panel-list">
{this.state.person.map((item, i) =>{
return(
<h1>{item.name.first}</h1>
<span>{item.cell}, {item.email}</span>
)
})}
<div>
</div>
)
}
}
javascript
jquery
reactjs
Raj Rj
źródło
źródło
componentDidMount
wywołaniu zwrotnym.fetch()
zamiast jQuery, jeśli używasz jQuery tylko do wykonywania żądań Ajax.useEffect
prawdopodobnie jest to miejsce, w którym można teraz umieszczać wywołania interfejsu API. Zobacz btholt.github.io/complete-intro-to-react-v5/effectsOdpowiedzi:
W takim przypadku możesz wykonać wywołanie Ajax wewnątrz
componentDidMount
, a następnie zaktualizowaćstate
export default class UserList extends React.Component { constructor(props) { super(props); this.state = {person: []}; } componentDidMount() { this.UserList(); } UserList() { $.getJSON('https://randomuser.me/api/') .then(({ results }) => this.setState({ person: results })); } render() { const persons = this.state.person.map((item, i) => ( <div> <h1>{ item.name.first }</h1> <span>{ item.cell }, { item.email }</span> </div> )); return ( <div id="layout-content" className="layout-content-wrapper"> <div className="panel-list">{ persons }</div> </div> ); } }
źródło
Możesz sprawdzić architekturę Flux . Polecam również zapoznać się z implementacją React-Redux . Umieść wywołania interfejsu API w swoich działaniach. Jest znacznie czystszy niż włożenie wszystkiego do komponentu.
Akcje to rodzaj metod pomocniczych, które można wywołać, aby zmienić stan aplikacji lub wykonać wywołania interfejsu API.
źródło
Użyj
fetch
metody wewnątrz,componentDidMount
aby zaktualizować stan:componentDidMount(){ fetch('https://randomuser.me/api/') .then(({ results }) => this.setState({ person: results })); }
źródło
Ta dyskusja trwała już jakiś czas, a odpowiedź @Alexander T. była dobrym przewodnikiem do naśladowania dla nowszych React, takich jak ja. I podzielę się kilkoma dodatkowymi wiedzą na temat wielokrotnego wywoływania tego samego API w celu odświeżenia komponentu. Myślę, że jest to prawdopodobnie powszechny problem, z którym nowicjusz może napotkać na początku.
componentWillReceiveProps(nextProps)
z oficjalnej dokumentacji :Możemy wywnioskować, że tutaj jest miejsce, w którym obsługujemy właściwości z komponentu nadrzędnego, mamy wywołania API i stan aktualizacji.
Bazuj na przykładzie @Alexander T.:
export default class UserList extends React.Component { constructor(props) { super(props); this.state = {person: []}; } componentDidMount() { //For our first load. this.UserList(this.props.group); //maybe something like "groupOne" } componentWillReceiveProps(nextProps) { // Assuming parameter comes from url. // let group = window.location.toString().split("/")[*indexParameterLocated*]; // this.UserList(group); // Assuming parameter comes from props that from parent component. let group = nextProps.group; // Maybe something like "groupTwo" this.UserList(group); } UserList(group) { $.getJSON('https://randomuser.me/api/' + group) .then(({ results }) => this.setState({ person: results })); } render() { return (...) } }
Aktualizacja
componentWillReceiveProps()
zostanie wycofany.Oto tylko niektóre metody (wszystkie w Doc ) w cyklu życia, które moim zdaniem byłyby związane z wdrażaniem API w ogólnym przypadku:
Odnosząc się do powyższego schematu:
Wdróż interfejs API w
componentDidMount()
Właściwy scenariusz wywołania API jest taki, że zawartość (z odpowiedzi API) tego komponentu będzie statyczna,
componentDidMount()
uruchamiana tylko raz podczas montowania komponentu, nawet nowe właściwości są przekazywane z komponentu nadrzędnego lub mają działania do wykonaniare-rendering
.Komponent sprawdza różnicę, aby ponownie renderować, ale nie montować ponownie .
Cytat z doc :
static getDerivedStateFromProps(nextProps, prevState)
Powinniśmy zauważyć, że istnieją dwa rodzaje aktualizacji komponentów ,
setState()
w obecnym komponencie nie spowodowałoby to wyzwolenia tej metody, ale ponowne renderowanie lub nowe właściwości z komponentu nadrzędnego tak. Mogliśmy się dowiedzieć, że ta metoda również strzela podczas montażu.Jest to właściwe miejsce na wdrożenie API, jeśli chcemy użyć obecnego komponentu jako szablonu, a nowe parametry API to właściwości pochodzące z komponentu nadrzędnego .
Otrzymujemy inną odpowiedź z API i zwracamy
state
tutaj nową , aby zmienić zawartość tego komponentu.Na przykład:
Mamy listę rozwijaną dla różnych samochodów w komponencie nadrzędnym, ten komponent musi wyświetlać szczegóły wybranego.
componentDidUpdate(prevProps, prevState)
W odróżnieniu od
static getDerivedStateFromProps()
tej metody jest wywoływana natychmiast po każdym renderowaniu, z wyjątkiem renderowania początkowego. Moglibyśmy wywołać API i renderować różnicę w jednym komponencie.Rozszerz poprzedni przykład:
Komponent pokazujący szczegóły samochodu może zawierać listę serii tego samochodu, jeśli chcemy sprawdzić wersję produkcyjną z 2013 roku, możemy kliknąć lub wybrać lub ... element listy, który będzie prowadził jako pierwszy,
setState()
aby to odzwierciedlić zachowanie (takie jak podświetlanie pozycji listy) w tym komponencie, aw dalszej częścicomponentDidUpdate()
wysyłamy nasze żądanie z nowymi parametrami (stan). Po otrzymaniu odpowiedzisetState()
ponownie wykonujemy renderowanie innej zawartości szczegółów samochodu. Aby następujące elementy niecomponentDidUpdate()
powodowały pętli nieskończoności, musimy porównać stan, używającprevState
na początku tej metody, aby zdecydować, czy wyślemy API i wyrenderujemy nową zawartość.Ta metoda naprawdę mogłaby być użyta tak jak w
static getDerivedStateFromProps()
przypadku rekwizytów, ale trzeba obsługiwać zmianyprops
poprzez wykorzystanieprevProps
. Musimy współpracować,componentDidMount()
aby obsłużyć początkowe wywołanie API.Cytat z doc :
źródło
Chciałbym, abyś rzucił okiem na redux http://redux.js.org/index.html
Mają bardzo dobrze zdefiniowany sposób obsługi wywołań asynchronicznych, czyli wywołań API, i zamiast używać jQuery do wywołań API, polecam używanie pakietów fetch lub request npm, pobieranie jest obecnie obsługiwane przez nowoczesne przeglądarki, ale dostępna jest również podkładka dla po stronie serwera.
Jest też inny niesamowity superagent pakietu , który ma wiele opcji podczas wysyłania żądań API i jest bardzo łatwy w użyciu.
źródło
Funkcja renderowania powinna być czysta, oznacza to, że do renderowania używa tylko stanu i właściwości, nigdy nie próbuj modyfikować stanu w renderowaniu, zwykle powoduje to brzydkie błędy i znacznie zmniejsza wydajność. Jest to również dobry punkt, jeśli oddzielisz pobieranie danych i problemy z renderowaniem w aplikacji React. Polecam przeczytanie tego artykułu, który bardzo dobrze wyjaśnia ten pomysł. https://medium.com/@learnreact/container-components-c0e67432e005#.sfydn87nm
źródło
Ta część dokumentacji React v16 odpowie na twoje pytanie, przeczytaj o componentDidMount ():
Jak widzisz, componentDidMount jest uważane za najlepsze miejsce i cykl do wykonania wywołania interfejsu API , a także uzyskania dostępu do węzła, co oznacza, że w tym czasie można bezpiecznie wykonać wywołanie, zaktualizować widok lub cokolwiek zrobić, gdy dokument jest gotowy, jeśli jesteś używając jQuery, powinno jakoś przypomnieć Ci funkcję document.ready (), w której możesz upewnić się, że wszystko jest gotowe na wszystko, co chcesz zrobić w swoim kodzie ...
źródło
1) Możesz użyć F etch API do pobierania danych z Endd Points:
Przykład pobierania całego
Github
odpoczynku dla użytkownika/* Fetch GitHub Repos */ fetchData = () => { //show progress bar this.setState({ isLoading: true }); //fetch repos fetch(`https://api.github.com/users/hiteshsahu/repos`) .then(response => response.json()) .then(data => { if (Array.isArray(data)) { console.log(JSON.stringify(data)); this.setState({ repos: data , isLoading: false}); } else { this.setState({ repos: [], isLoading: false }); } }); };
2) Inną alternatywą jest Axios
import axios from "axios"; /* Fetch GitHub Repos */ fetchDataWithAxios = () => { //show progress bar this.setState({ isLoading: true }); // fetch repos with axios axios .get(`https://api.github.com/users/hiteshsahu/repos`) .then(result => { console.log(result); this.setState({ repos: result.data, isLoading: false }); }) .catch(error => this.setState({ error, isLoading: false }) ); }
Teraz możesz wybrać pobieranie danych przy użyciu dowolnej z tych strategii w
componentDidMount
class App extends React.Component { state = { repos: [], isLoading: false }; componentDidMount() { this.fetchData (); }
W międzyczasie możesz wyświetlić pasek postępu podczas ładowania danych
{this.state.isLoading && <LinearProgress />}
źródło
Możesz także pobierać dane z zaczepami w komponentach funkcji
pełny przykład z wywołaniem api: https://codesandbox.io/s/jvvkoo8pq3
drugi przykład: https://jsfiddle.net/bradcypert/jhrt40yv/6/
const Repos = ({user}) => { const [repos, setRepos] = React.useState([]); React.useEffect(() => { const fetchData = async () => { const response = await axios.get(`https://api.github.com/users/${user}/repos`); setRepos(response.data); } fetchData(); }, []); return ( <div> {repos.map(repo => <div key={repo.id}>{repo.name}</div> )} </div> ); } ReactDOM.render(<Repos user="bradcypert" />, document.querySelector("#app"))
źródło
Najlepszym miejscem i praktyką dla zewnętrznych wywołań API jest metoda React Lifecycle componentDidMount () , gdzie po wykonaniu wywołania API należy zaktualizować stan lokalny do wyzwolenia nowego wywołania metody render () , wtedy zmiany w zaktualizowanym stanie lokalnym będą zastosować w widoku komponentu.
Jako inną opcję dla początkowego wywołania zewnętrznego źródła danych w Reakcie wskazano konstruktor () metoda klasy. Konstruktor jest pierwszą metodą wykonywaną podczas inicjowania instancji obiektu składnika. Takie podejście można zobaczyć w przykładach dokumentacji dla komponentów wyższego rzędu .
Metody componentWillMount () i UNSAFE_componentWillMount () nie powinny być używane do zewnętrznych wywołań API, ponieważ mają być przestarzałe.Tutaj możesz zobaczyć typowe powody, dla których ta metoda zostanie wycofana.
W każdym razie nigdy nie wolno używać metody render () ani metody wywoływanej bezpośrednio z metody render () jako punktu wywołania zewnętrznego interfejsu API. Jeśli to zrobisz, Twoja aplikacja zostanie zablokowana .
źródło
Czystym sposobem jest wykonanie asynchronicznego wywołania API wewnątrz componentDidMount za pomocą funkcji try / catch .
Kiedy wywołaliśmy API, otrzymujemy odpowiedź. Następnie stosujemy na nim metodę JSON, aby przekonwertować odpowiedź na obiekt JavaScript. Następnie pobieramy z tego obiektu odpowiedzi tylko jego obiekt potomny o nazwie „results” (data.results).
Na początku zdefiniowaliśmy „userList” w stanie jako pustą tablicę. Jak tylko wykonamy wywołanie API i otrzymamy dane z tego API, przypisujemy "wyniki" do userList przy użyciu metody setState .
Wewnątrz funkcji renderującej mówimy, że userList będzie pochodzić ze stanu. Ponieważ userList jest tablicą obiektów, które mapujemy za jej pomocą, wyświetlamy obraz, nazwę i numer telefonu każdego obiektu „user”. Aby uzyskać te informacje, używamy notacji kropkowej (np. Użytkownik.telefon).
UWAGA : w zależności od interfejsu API Twoja odpowiedź może wyglądać inaczej. Console.log całą „odpowiedź”, aby zobaczyć, jakich zmiennych z niej potrzebujesz, a następnie przypisz je w setState.
UserList.js
import React, { Component } from "react"; export default class UserList extends Component { state = { userList: [], // list is empty in the beginning error: false }; componentDidMount() { this.getUserList(); // function call } getUserList = async () => { try { //try to get data const response = await fetch("https://randomuser.me/api/"); if (response.ok) { // ckeck if status code is 200 const data = await response.json(); this.setState({ userList: data.results}); } else { this.setState({ error: true }) } } catch (e) { //code will jump here if there is a network problem this.setState({ error: true }); } }; render() { const { userList, error } = this.state return ( <div> {userList.length > 0 && userList.map(user => ( <div key={user}> <img src={user.picture.medium} alt="user"/> <div> <div>{user.name.first}{user.name.last}</div> <div>{user.phone}</div> <div>{user.email}</div> </div> </div> ))} {error && <div>Sorry, can not display the data</div>} </div> ) }}
źródło
Byłoby wspaniale użyć axios dla żądania api, które obsługuje anulowanie, przechwytywacze itp. Wraz z axios, używam re-redux do zarządzania stanem i redux-saga / redux-thunk do efektów ubocznych.
źródło