import React, {Component} from 'react';
import "./DisplayCard.css";

class DisplayCard extends Component {
runArray = (array) => {
  for (var i = 0; i<array.length; i++) {
    return <div>{array[i].task}</div>
  }
}

renderElements = (savedTasks) =>{
  if (savedTasks.length === 0) {
    return <div className="noTasks"> <p>You have no saved tasks.</p> </div>
  } else {
    return this.runArray(savedTasks)
  }
}


render() {
  return (
  <div className="DisplayCardContainer">
    {this.renderElements(this.props.saved)}
  </div>
  )
}
}
export default DisplayCard;

Salut les gars,

Je suis nouveau pour réagir, c'est donc mon composant enfant qui prend l'état de son composant parent. Mon objectif est de restituer le composant chaque fois que le tableau this.props.saved est modifié.

Ce composant affiche: <p>You have no saved tasks.</p> lorsque le this.props.saved.length === 0 et il rend <div>{array[0].task}</div> lorsque j'entre dans la première tâche, mais il le garde à <div>{array[0].task}</div> après cela. Je constate que l'état ne cesse de changer et que this.props.saved continue de s'agrandir, mais mon composant ne change plus.

0
skypen 27 janv. 2019 à 00:27

5 réponses

Meilleure réponse

Voici votre problème:

runArray = (array) => {
   for (var i = 0; i<array.length; i++) {
     //the first time we get here, it immediately ends the function!
     return <div>{array[i].task}</div>
   }
}

Cette boucle ne passe qu'une seule fois (à i=0) puis revient, quittant la fonction runArray et annulant le reste de la boucle. Vous souhaitiez probablement renvoyer un tableau d'éléments, un pour chacune des tâches. Je recommande d'utiliser Array.map() pour cela, qui prend un tableau et transforme chaque élément, créant un nouveau tableau:

runArray = (array) => {
    return array.map(arrayElement => <div>arrayElement.task</div>);
}

Cela devrait faire l'affaire. Notez que React peut se plaindre du fait que vos éléments n'ont pas la propriété key - voir la documentation pour plus d'informations: https://reactjs.org/docs/lists-and-keys.html

2
Duncan Thacker 26 janv. 2019 à 21:34

Vous devez mettre à jour l'état du composant pour déclencher la fonction de rendu. Votre fonction de rendu n'est pas déclenchée car vous n'avez pas mis à jour l'état lorsque les accessoires ont changé. Il existe de nombreuses façons de mettre à jour l'état lorsque les accessoires sont mis à jour. Une méthode peut être la suivante:

componentWillReceiveProps(nextProps){
  if (nextProps.saved !== this.props.saved) {
    this.setState({ saved: nextProps.saved })
  }
}

Modifiez également votre fonction de rendu pour utiliser l'état du composant comme ci-dessous:

renderElements = () =>{
  if (this.state.savedTasks.length === 0) {
    return <div className="noTasks"> <p>You have no saved tasks.</p> </div>
  } else {
    return this.runArray(this.state.savedTasks)
  }
}
0
mstfyldz 26 janv. 2019 à 21:37

C'est parce que vous écrivez mal la fonction runArray. Vous effectuez un retour dans la boucle for pour qu'il se casse après la première itération. Il n'itérera pas sur l'ensemble du tableau.

Vous devez transformer votre boucle for en carte: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map

runArray = (array) => {
  return array.map(v => <div>{v.task}</div>)
}

Est-ce que cela résout votre problème?

1
BenoitVasseur 26 janv. 2019 à 21:36

Le problème vient de votre fonction runArray. À l'intérieur de votre boucle, vous retournez le premier élément et c'est tout. Je suppose que vous ne voyez que la première entrée?

Lorsque vous essayez de rendre toutes vos tâches, je vous suggère de mapper vos tâches, par exemple

runArray = (array) => array.map(entry => <div>{entry.task}</div>)
1
Martin Seeler 26 janv. 2019 à 21:35

Utilisez .map pour qu'il rende votre tâche correctement. Vous pouvez supprimer runArray et vous reposer entièrement sur les accessoires, vous n'avez donc pas besoin de passer d'arguments entre les fonctions, car cela peut rapidement devenir compliqué. Voici un exemple rapide de la façon de créer un composant parent dans lequel vous pouvez ajouter une tâche et les passer dans un composant afin qu'il restitue vos données lorsque les accessoires sont modifiés, le rendant ainsi réactif.

class App extends React.Component {
  state = {
    taskLabel: "",
    tasks: [
      {
        id: 1,
        label: "Do something"
      },
      {
        id: 2,
        label: "Learn sometihng"
      }
    ]
  };

  handleInput = evt => {
    this.setState({
      [evt.target.name]: evt.target.value
    });
  };

  handleSubmit = evt => {
    evt.preventDefault();
    this.setState(prevState => ({
      taskLabel: "",
      tasks: [
        ...prevState.tasks,
        {
          id: prevState.tasks.length + 1,
          label: this.state.taskLabel
        }
      ]
    }));
  };

  render() {
    return (
      <div>
        <form onSubmit={this.handleSubmit}>
          <input
            name="taskLabel"
            type="text"
            placeholder="Task label"
            value={this.state.taskLabel}
            onChange={this.handleInput}
          />
          <button>Create task</button>
        </form>
        <DisplayCard tasks={this.state.tasks} />
      </div>
    );
  }
}

class DisplayCard extends React.Component {
  renderTasks = () => {
    if (this.props.tasks.length !== 0) {
      return this.props.tasks.map(task => (
        <div key={task.id}>{task.label}</div>
      ));
    } else {
      return <div>No tasks</div>;
    }
  };

  render() {
    return <div>{this.renderTasks()}</div>;
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
0
Win 26 janv. 2019 à 21:40