Je suis nouveau pour réagir et j'ai une question sur une meilleure pratique qui me fait faire une erreur. J'appelle une API pour récupérer des informations et modifier un tableau dans l'état une fois que la réponse est renvoyée par l'API. Dans le "rendu", je dois récupérer les informations de ce tableau (quand il est terminé) ou il me renvoie une erreur car le tableau est vide lorsque le rendu est initialisé.
class MyClass extends React.Component { constructor(props) { super(props) this.state = { activeIndex: 0, items: [] } } componentDidMount() { axios .get(`API_ADDRESS`, { headers: { Authorization: `Token XXX`, }, }) .then(function(response) { this.setState({ items: response.results, }) }) .catch(error => { notification.warning({ message: error.code, description: error.message, }) }) } changeDialog = (e, index) => { e.preventDefault() this.setState({ activeIndex: index, }) } render() { const { activeIndex, items } = this.state const { first_name: firstName, last_name: lastName, phone, email, address, } = items[activeIndex]
3 Réponses :
Parce que l'API que vous récupérez du serveur est asynchrone . Lors du premier rendu de Component, les données que vous setState dans axios n'ont pas encore mises à jour, elles ont juste été mises à jour lors du deuxième rendu du Component.
Vous devez donc vérifier l'état dans le composant de rendu comme celui-ci pour vous assurer que si activeIndex est défini
alors déclarez la variable avec items [activeIndex]
:
activeIndex && const { first_name: firstName, last_name: lastName, phone, email, address, } = items[activeIndex]
changez simplement votre composant comme ceci:
constructor(props) { super(props) this.state = { activeIndex: 0, items: [], isFetching: false } } componentDidMount() { // staring your fetching this.setState({isFetching: true}); axios .get(`API_ADDRESS`, { headers: { Authorization: `Token XXX`, }, }) .then(function(response) { // finish fetching when your response is ready :) this.setState({ items: response.results, isFetching: false }); }) .catch(error => { // finish fetchnig this.setState({isFetching: false}) notification.warning({ message: error.code, description: error.message, }) }) } changeDialog = (e, index) => { e.preventDefault() this.setState({ activeIndex: index, }) } render() { // if your component is while fetching shows a loading to the user if(this.state.isFetching) return <div>Loading...</div>; // if there is no results shows a msg to the user if(this.state.items.length === 0) return <div>there is not items!!!</div> const { activeIndex, items } = this.state const { first_name: firstName, last_name: lastName, phone, email, address, } = items[activeIndex]
Deux problèmes:
ceci
dans la Promesse
renvoyée par axios. Vous utilisez function () {}
donc le this
à l'intérieur n'est pas l'instance du composant. Changez-le en fonction de flèche. undefined
lorsque activeIndex
pointe vers un élément item
qui n’est pas là (ce qui se produit dans le chargement initial avant que l'axios ne récupère les données). Fix :
// ... (code not shown remains unmodified) componentDidMount() { axios .get(`API_ADDRESS`, { headers: { Authorization: `Token XXX`, }, }) .then(response => { // changed this line this.setState({ items: response.results, }) }) // ... (code not shown remains unmodified) render() { const { activeIndex, items } = this.state if (!items[activeIndex]) { // added this line return <div>Hold tight while items are being fetched...</div>; // added this line } // added this line const { first_name: firstName, // ... (code not shown remains unmodified)
Je ne dirais pas que cela en aucune manière spécifique de réagir. Le problème est que vous essayez aveuglément de déstructurer les
éléments [activeIndex]
sans vous assurer que vous n'obtenez pas d'exception de référence nulle.