1
votes

Le composant React n'affiche pas le retour d'une fonction

J'ai un composant qui est censé afficher une "carte" contenant des informations enregistrées dans un tableau en état. J'obtiens ces informations à partir d'un fichier JSON et je les sauvegarde dans mon tableau dans un "componentDidMount". J'ai ensuite créé une fonction appelée "displayFood" avant le retour de ma fonction de rendu, que j'utilise ensuite dans mes fonctions de rendu. Le problème est que lorsque j'exécute le code, aucune carte n'est affichée.

import React from 'react'
import "./style.scss";
import FoodData from "./foodData.json";

class Food extends React.Component {
    constructor(props){
        super(props);
        this.state={
            foodData: []
        }
    }

    componentDidMount(){
        FoodData.map((foodItem,index) => {
            var foodTemp = {
                id: index,
                name: foodItem.name,
                pic: foodItem.pic,
                serving: foodItem.serving,
                calories: foodItem.calories,
                sugar: foodItem.sugar,
                protien: foodItem.protien
            }
            this.setState((prevState) => {
                prevState.foodData.push(foodTemp)
            })
        })
    }

  render() {

    const displayFood = () => {
        var i;
        for(i = 0; i < this.state.foodData.length; i++){
            return(
                <div className="food-card">
                    <img src={require(`${this.state.foodData[i].pic}`)}/>
                    <ul>
                        <li>{this.state.foodData[i].name}</li>
                        <li>Serving: {this.state.foodData[i].serving}</li>
                        <li>Calories: {this.state.foodData[i].calories}</li>
                        <li>Sugar: {this.state.foodData[i].sugar}</li>
                        <li>Protien: {this.state.foodData[i].protien}</li>
                    </ul>
                    <button name={this.state.foodData[i].name}>Add</button>
                </div>
            )
        }
    }

      return(
        <div>
            <div className="food-container">
            {
                displayFood()       
            }
            </div>
        </div>
      )
  }
}

export default Food;


0 commentaires

4 Réponses :


0
votes

Selon le cycle de vie, la méthode render est en fait déjà appelée avant componentDidMount . Par conséquent, au moment où elles sont rendues, les données sont toujours vides. Pourquoi ne pas déplacer l'initialisation des données dans componentWillMount ?


1 commentaires

Merci justelouise je suis allé de l'avant et j'ai changé le "DidMount" en "WillMount" et maintenant il affiche correctement le premier objet du tableau. J'espère que je pourrai comprendre pourquoi la boucle for ne me donne qu'un seul résultat. (j'ai essayé de vous voter mais parce que je n'ai pas de réputation sur ce site, cela ne montrera pas)



0
votes

essayez de changer l'état précédent ... vous avez utilisé directement les données sur l'état, cela ne change pas la racine de l'état:

this.setState((prevState) => ({
    ...prevState,
    foodData: [ ...foodData, foodTemp ],
}))


1 commentaires

Merci d'avoir apporté les modifications et obtenir le même résultat du programme affichant uniquement le premier élément dans le tableau d'état



2
votes

Premièrement, je ne suis pas sûr que votre setState dans componentDidMount fonctionne. Si vous ne souhaitez pas renvoyer un nouveau tableau, vous ne devez pas utiliser map , utilisez plutôt forEach . Et vous faites muter directement l'état, ce qui n'est pas recommandé. La fonction devrait ressembler à ceci:

const displayFood = () => {
    let cards = [] // Crate an array
    for(let i = 0; i < this.state.foodData.length; i++){
        cards.push( // push item to array through the loop
            <div className="food-card">
                <img src={require(`${this.state.foodData[i].pic}`)}/>
                <ul>
                    <li>{this.state.foodData[i].name}</li>
                    <li>Serving: {this.state.foodData[i].serving}</li>
                    <li>Calories: {this.state.foodData[i].calories}</li>
                    <li>Sugar: {this.state.foodData[i].sugar}</li>
                    <li>Protien: {this.state.foodData[i].protien}</li>
                </ul>
                <button name={this.state.foodData[i].name}>Add</button>
            </div>
        )
    }
  return cards  // Return the array
}

Deuxièmement, return dans la boucle for ne renverra que le premier élément. Vous devez créer un tableau puis pousser l'élément à travers la boucle au lieu de retourner

componentDidMount(){
  // Build a new array of object from FoodData
  const newFoodData = 
        FoodData.map(({name, pic, serving, calories, sugar, protien }, index) => 
                     ({ id: index, name, pic, serving, calories, sugar, protien }))
  // Assign the new object to state
  this.setState({ foodData: newFoodData })
}

Et je vous recommande de déplacer le displayFood en dehors du rendu () fonction. Parce que lorsque d'autres choses provoquent un nouveau rendu mais pas le changement de this.state.foodData , le composant doit reconstruire le displayFood () . C'est gaspillé.


3 commentaires

Dam bird vous l'avez cloué sur la tête. J'ai mis en œuvre vos suggestions en changeant le "DidMount" en "WillMount" et cela fonctionne très bien. J'aurais aimé avoir plus de réputation de stackoverflow pour vous donner un vote positif visible. Merci encore


Je vous en prie! En fait, vous devriez le mettre dans componentDidMount , il suffit d'ajouter handle le fooData vide dans la fonction render (). c'est-à-dire if (! this.state.dataFood.length) renvoie

Loading...

. Parce que, dans une application réelle, les données ne proviendront pas du fichier JSON mais de l'API, componentWillMount ne peut pas vous aider à ce moment-là. Et à partir de la version 17, 'componentWillMount' sera obsolète reactjs.org/docs/react-component .html # unsafe_componentwillmo‌ unt


Grand à savoir et fera. J'ai entendu parler de la dépréciation de "compnentWillMount" mais je ne l'avais pas encore examiné. Vous semblez très bien informé sur React.



0
votes
class Hello extends React.Component {

    constructor(props){
    super(props);
    this.state={
      foodData: []
    }
  }

  componentDidMount(){
    const  { foodData } = this.state;

    foodData.push({
        id: 0,
      name: 'beans',
      pic: 'picurl',
      serving: '2',
      calories: '100',
      sugar: '30',
      protien: '10'
    });

    this.setState({ foodData });

  }

  render() {
    return <div>
      <div className="food-container">
        {
          this.state.foodData.map((item,key) => {
            return <div className="food-card">
              {`${item.pic}`}
              <ul>
                <li>{item.name}</li>
                <li>Serving: {item.serving}</li>
                <li>Calories: {item.calories}</li>
                <li>Sugar: {item.sugar}</li>
                <li>Protien: {item.protien}</li>
              </ul>
              <button name={item.name}>Add</button>
            </div>
          })     
        }
      </div>

    </div>;
  }
}

ReactDOM.render(
  <Hello />,
  document.getElementById('container')
);


make sure that your foodData is loaded correctly on 'componentDidMount()'https://jsfiddle.net/leolima/L7c418kp/13/

1 commentaires

Merci pour la réponse Leo. Il semble que cela fonctionnerait également, mais j'ai déjà une réponse solide de Bird. Merci de votre aide.