J'ai un objet d'état qui contient un tableau d'objets:
export default class StatePractice extends React.Component { constructor() { super(); this.state = { feeling: [ { name: 'alert', status: false }, { name: 'calm', status: false }, { name: 'creative', status: false }, { name: 'productive', status: false }, { name: 'relaxed', status: false }, { name: 'sleepy', status: false }, { name: 'uplifted', status: false } ] } } buttonToggle = (event) => { event.persist(); const value = !event.target.value this.setState( prevState => ({ status: !prevState.status })) } render() { return ( <div> { this.state.feeling.map( (stateObj, index) => { return <button key={ index } onClick={ this.buttonToggle } value={ stateObj.status } > { stateObj.status.toString() } </button> } ) } </div> ) } }
Je veux faire basculer le status
booléen de vrai à faux lors d'un événement de clic. J'ai construit cette fonction en tant que gestionnaire de clics mais cela ne connecte pas l'événement au changement d'état:
buttonToggle = (event) => { event.persist(); const value = !event.target.value this.setState( prevState => ({ status: !prevState.status })) }
J'ai du mal à suivre le flux de contrôle de l'imbriqué Réagir au changement d'état, et comment l'événement actif fait le saut du gestionnaire à l'objet d'état et vice versa.
L'ensemble du composant:
this.state = { feeling: [ { name: 'alert', status: false }, { name: 'calm', status: false }, { name: 'creative', status: false }, { name: 'productive', status: false }, { name: 'relaxed', status: false }, { name: 'sleepy', status: false }, { name: 'uplifted', status: false } ] }
3 Réponses :
Afin de résoudre votre problème, vous devez d'abord envoyer l'index de l'élément qui va être modifié à votre fonction bascule:
buttonToggle = index => event => { event.persist(); const feeling = [...this.state.feeling]; //Copy your array feeling[index] = !feeling[index]; this.setState({ feeling }); }
Ensuite, ajustez la fonction pour recevoir à la fois l'index et l'événement.
Maintenant, pour modifier votre tableau d'état, copiez-le, changez la valeur que vous recherchez et remettez-le dans votre état:
onClick = {this.buttonToggle(index)}
Vous pouvez également utiliser slice
pour copier votre tableau, ou même envoyer directement un tableau mappé
où une seule valeur est modifiée.
La mise à jour d'un objet imbriqué dans un objet à état de réaction est délicate. Vous devez obtenir l'objet entier de l'état dans une variable temporaire, mettre à jour la valeur dans cette variable, puis remplacer l'état par la variable mise à jour. Pour ce faire, votre fonction buttonToggle doit savoir quel bouton a été enfoncé.
buttonToggle = (event, name) => { event.persist(); let { feeling } = this.state; feeling[name] = !feeling[name]; this.setState({ feeling }); }
Et votre fonction buttonToggle pourrait ressembler à ceci
feeling: { alert: false, calm: false, creative: false, etc... }
Voici un JSFiddle fonctionnel.
Alternativement, si vous n'en avez pas besoin pour stocker plus de données par sentiment que "nom" et "statut", vous pouvez réécrire l'état de votre composant comme ceci:
buttonToggle = (event, name) => { event.persist(); let { feeling } = this.state; let newFeeling = []; for (let index in feeling) { let feel = feeling[index]; if (feel.name == name) { feel = {name: feel.name, status: !feel.status}; } newFeeling.push(feel); } this.setState({ feeling: newFeeling, }); }
Et buttonToggle:
return <button key={ index } onClick={ (event) => this.buttonToggle(event, stateObj.name) } value={ stateObj.status } > { stateObj.status.toString() } </button>
Excellente réponse, bienvenue à SO. Le consensus semble être que vous devez réécrire le tableau entier dans setState. Est-ce une exigence, semble très peu performant.
@staypuftman C'est redondant, mais actuellement le seul moyen. React ne gère pas très bien l'état imbriqué. Une approche alternative serait soit de 1. concevoir des composants de réaction (plus petits) qui effectuent une tâche spécifique (et de réduire la complexité de l'objet d'état) ou 2. d'envisager d'implémenter un redux dans react. Je recommande d'examiner les deux.
intéressant, explique pourquoi toutes mes tentatives n'ont pas fonctionné - je n'avais pas le bon cadre. Également intéressant de mentionner redux. Ce morceau d'État est en fait dans un contexte en ce moment, mais il semble que j'ai atteint la limite de ce que cela peut faire. Mon site n'est pas super fou donc je pense que ça ira. Merci encore.
Je pense que vous devez mettre à jour tout le tableau lorsque vous recevez l'événement. Et il vaut mieux ne pas muter l'état existant. Je recommanderais le code suivant
export default class StatePractice extends React.Component { constructor() { super(); this.state = { feeling: [ { name: "alert", status: false }, { name: "calm", status: false }, { name: "creative", status: false }, { name: "productive", status: false }, { name: "relaxed", status: false }, { name: "sleepy", status: false }, { name: "uplifted", status: false }, ], }; } buttonToggle = (index, value) => (event) => { event.persist(); const toUpdate = { ...this.state.feeling[index], status: !value }; const feeling = [...this.state.feeling]; feeling.splice(index, 1, toUpdate); this.setState({ feeling, }); }; render() { return ( <div> {this.state.feeling.map((stateObj, index) => { return ( <button key={index} onClick={this.buttonToggle(index, stateObj.status)} value={stateObj.status} > {stateObj.status.toString()} </button> ); })} </div> ); } }
Donc, vous avez imbriqué l'événement dans une autre fonction de buttonToggle - pourquoi?
J'ai imbriqué le buttonToggle pour renvoyer la fonction parce que je veux réutiliser l'index et la valeur de statut de l'élément et le gestionnaire d'événements est une fonction, donc je les combine simplement :)
Je veux faire basculer le statut booléen de vrai à faux lors d'un événement de clic. Dans tous les objets ou dans un objet spécifique?
Votre état initial contient un tableau d'objets, mais vous passez ensuite l'objet single dans
setState
. C'est probablement le problème.@hindmost - Je veux juste basculer le statut sur un élément à la fois - celui sur lequel on clique.