1
votes

React - Chargement des données avant le rendu

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]


1 commentaires

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.


3 Réponses :


1
votes

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]


0 commentaires

0
votes

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]


0 commentaires

0
votes

Deux problèmes:

  • méfiez-vous de 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.
  • ajoutez une garde pour ne pas détruire 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)


0 commentaires