Je suis récemment passé de Angular à ReactJs. J'utilise jQuery pour les appels d'API. J'ai une API qui renvoie une liste d'utilisateurs aléatoire à imprimer dans une liste.
Je ne sais pas comment écrire mes appels d'API. Quelle est la meilleure pratique pour cela?
J'ai essayé ce qui suit mais je ne reçois aucune sortie. Je suis ouvert à la mise en œuvre de bibliothèques API alternatives si nécessaire.
Voici mon code:
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>
)
}
}
Dans ce cas, vous pouvez faire un appel ajax à l'intérieur de componentDidMount
, puis mettre à jour 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>
);
}
}
Vous voudrez peut-être consulter le Flux Architecture . Je recommande également de vérifier implémentation de React-Redux . Mettez vos appels api dans vos actions. C'est beaucoup plus propre que de tout mettre dans le composant.
Les actions sont en quelque sorte des méthodes d'assistance que vous pouvez appeler pour modifier l'état de votre application ou effectuer des appels d'API.
Utilisez fetch
méthode à l'intérieur de componentDidMount
pour mettre à jour l'état. comme ci-dessous
....
componentDidMount(){
fetch('https://randomuser.me/api/')
.then(({ results }) => this.setState({ person: results }));
}
....
J'aimerais que vous regardiez redux http://redux.js.org/index.html
Ils ont un moyen très bien défini de gérer les appels asynchrones, c’est-à-dire les appels API, et au lieu d’utiliser jQuery pour les appels API, je vous recommande d’utiliser fetch ou demande les paquets npm, fetch est actuellement pris en charge par les navigateurs modernes, mais une est également disponible pour le côté serveur.
Il y a aussi un autre paquet étonnant superagent, qui a beaucoup d'options pour faire une demande d'API et qui est très facile à utiliser. .
Cette discussion dure depuis un certain temps et la réponse de @Alexander T. constitue un bon guide à suivre pour les personnes qui réagissent comme moi. Et je vais partager un savoir-faire supplémentaire sur cette discussion concernant un problème probablement commun auquel les débutants peuvent être confrontés au début.
componentWillReceiveProps(nextProps)
, from documentation officielle :
Si vous devez mettre à jour l'état en réponse aux modifications de prop (par exemple, pour le réinitialiser), vous pouvez comparer this.props et nextProps et effectuer des transitions d'état à l'aide de this.setState () dans cette méthode.
Nous pourrions en conclure que c’est ici que nous gérons nos paramètres, qui peuvent provenir de la forme d’une URL ou des accessoires du composant parent, d’un appel API et de l’état de la mise à jour.
Base sur l'exemple de @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 (...)
}
}
componentWillReceiveProps()
serait obsolète.
Voici seulement quelques méthodes (toutes en Doc ) du cycle de vie qui, à mon avis, seraient liées au déploiement de l'API dans cas général:
En se référant au schéma ci-dessus:
Déployer l'API dans componentDidMount()
Le scénario approprié pour appeler l'API ici est que le contenu (à partir de la réponse de l'API) de ce composant sera statique, componentDidMount()
ne se déclenchera qu'une fois pendant le montage du composant, même les nouveaux accessoires seront passés du composant parent ou auront des actions à mener re-rendering
.
Le composant vérifie la différence de re-rendre mais pas de remonter .
Extrait de doc :
Si vous devez charger des données depuis un point de terminaison distant, c’est un bon emplacement pour instancier la requête réseau.
static getDerivedStateFromProps(nextProps, prevState)
On notera qu’il existe deux types de mise à jour de composant , setState()
dans le composant actuel non ne déclencherait pas cette méthode, mais rendrait de nouveau ou de nouveaux accessoires à partir du composant parent faire. Nous avons découvert que cette méthode se déclenche également lors du montage.
C'est un endroit approprié pour déployer l'API si nous voulons utiliser le composant actuel comme un modèle, et que les nouveaux paramètres de l'API sont des accessoires provenant du composant parent .
Nous recevons une réponse différente de l’API et renvoyons new state
ici pour modifier le contenu de ce composant.
Par exemple:
Nous avons une liste déroulante pour différentes voitures dans le composant parent, ce composant doit afficher les détails de celui sélectionné.
componentDidUpdate(prevProps, prevState)
À la différence de static getDerivedStateFromProps()
, cette méthode est appelée immédiatement après chaque rendu, à l'exception du rendu initial. Nous pourrions avoir des appels d'API et rendre la différence dans un composant.
Prolongez l'exemple précédent:
Le composant pour afficher les détails de la voiture peut contenir une liste de séries de cette voiture. Si nous souhaitons vérifier la production 2013, nous pouvons cliquer ou sélectionner ou ... l’élément de la liste pour diriger une première setState()
à refléter ce comportement (tel que la mise en surbrillance de l'élément de liste) dans ce composant et dans la suivante componentDidUpdate()
, nous envoyons notre demande avec de nouveaux paramètres (état). Après avoir obtenu une réponse, nous avons à nouveau setState()
pour restituer le contenu différent des détails de la voiture. Pour empêcher la componentDidUpdate()
suivante de provoquer la boucle infini, nous devons comparer l'état en utilisant prevState
au début de cette méthode pour décider si nous envoyons l'API et restituons le nouveau contenu.
Cette méthode pourrait vraiment être utilisée comme static getDerivedStateFromProps()
avec des accessoires, mais il faudrait gérer les changements de props
en utilisant prevProps
. Et nous devons coopérer avec componentDidMount()
pour gérer l'appel initial de l'API.
Citation de doc :
... C’est aussi un bon endroit pour faire des requêtes réseau tant que vous comparez les accessoires actuels aux accessoires précédents ...
La fonction de rendu doit être pure, c'est-à-dire qu'elle utilise uniquement l'état et les accessoires pour le rendu, n'essayez jamais de modifier l'état du rendu, cela provoque généralement des bugs laids et une diminution significative des performances. C'est également un bon point si vous séparez la récupération des données et les problèmes de rendu dans votre React App. Je vous recommande de lire cet article qui explique très bien cette idée. https://medium.com/@learnreact/container-components-c0e67432e005#.sfydn87nm
Cette partie de React v16 La documentation répondra à votre question, continuez à lire à propos de composantDidMount ():
composantDidMount ()
composantDidMount () est appelé immédiatement après le montage d'un composant. L'initialisation nécessitant des nœuds DOM doit être effectuée ici. Si vous devez charger des données depuis un point de terminaison distant, c’est un bon emplacement pour instancier la requête réseau. Cette méthode est un bon endroit pour configurer des abonnements. Si vous faites cela, n’oubliez pas de vous désabonner dans composantWillUnmount ().
Comme vous le voyez, composantDidMount est considéré comme le meilleur endroit pour effectuer le cycle appel api, accédez également au nœud, ce qui signifie que vous pouvez désormais effectuer cet appel en toute sécurité, mettez à jour le afficher ou quoi que vous puissiez faire lorsque le document est prêt, si vous utilisez jQuery, il devrait vous rappeler en quelque sorte la fonction document.ready (), où vous pouvez vous assurer que tout est prêt pour tout ce que vous voulez faire dans votre code ...
1) Vous pouvez utiliser F Etch API pour récupérer les données de Endd Points:
Exemple de recherche de tous les Github
repos pour un utilisateur
/* 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) Autre alternative est Axios
Avec axios, vous pouvez réduire l’étape intermédiaire consistant à transmettre les résultats de la requête http à la méthode .json (). Axios ne fait que renvoyer l'objet de données que vous attendez.
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
})
);
}
Maintenant, vous pouvez choisir de récupérer des données en utilisant l’une de ces stratégies dans componentDidMount
class App extends React.Component {
state = {
repos: [],
isLoading: false
};
componentDidMount() {
this.fetchData ();
}
En attendant, vous pouvez afficher la barre de progression pendant le chargement des données
{this.state.isLoading && <LinearProgress />}
L'explication du code est dans le VIDEO . Une manière propre de faire un appel d'API asynchrone à l'intérieur de composantDidMount avec la fonction try/catch: UserList.js
import React, { Component } from "react";
import "./UserList.css";
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 className="list__container">
{userList.length > 0 && userList.map(user => (
<div className="list__item" key={user}>
<img src={user.picture.medium} className="list-item__photo" alt="user"/>
<div className="list-item__info-wrap">
<div className="list-item__name">{user.name.first}{user.name.last}</div>
<div className="list-item__phone">{user.phone}</div>
<div className="list-item__email">{user.email}</div>
</div>
</div>
))}
{error && <div>Sorry, can not display the data</div>}
</div>
)
}}
UserList.css
.list__container {
background: #0f0f0f;
color: #f2f2f2;
padding: 30px 0;
text-align: center;
}
.list__item {
display: flex;
align-items: center;
justify-content: center;
}
.list-item__photo {
width: 100px;
height: 100px;
border-radius: 50%;
}
.list-item__info-wrap {
margin-left: 20px;
text-align: left;
}
.list-item__name {
text-transform: capitalize;
}