Réagir (Facebook): état géré des cases à cocher contrôlées

J'ai un petit problème en essayant de créer une case à cocher qui sélectionne et désélectionne les autres cases individuelles (sélectionner / désélectionner tout) avec Réagir . J'ai lu http://facebook.github.io/react/docs/forms.html et j'ai découvert qu'il y avait des différences entre les " <input> " contrôlées et non contrôlées. Mon code de test est le suivant:

 var Test = React.createClass({ getInitialState: function() { return { data: [ { id: 1, selected: false }, { id: 2, selected: false }, { id: 3, selected: false }, { id: 4, selected: false } ] }; }, render: function() { var checks = this.state.data.map(function(d) { return ( <div> <input type="checkbox" data-id={d.id} checked={d.selected} onChange={this.__changeSelection} /> {d.id} <br /> </div> ); }); return ( <form> <input type="checkbox" ref="globalSelector" onChange={this.__changeAllChecks} />Global selector <br /> {checks} </form> ); }, __changeSelection: function(e) { var id = e.target.getAttribute('data-id'); var state = this.state.data.map(function(d) { return { id: d.id, selected: (d.id === id ? !d.selected : d.selected) }; }); this.setState({ data: state }); }, __changeAllChecks: function(e) { var value = this.refs.globalSelector.getDOMNode().checked; var state = this.state.data.map(function(d) { return { id: d.id, selected: value }; }); this.setState({ data: state }); } }); React.renderComponent(<Test />, document.getElementById('content')); 

Le «sélecteur global» fonctionne comme prévu: lorsque sélectionné, toutes les autres vérifications sont sélectionnées. Le problème est que le gestionnaire __changeSelection () n'est pas déclenché lorsque l'une des autres cases à cocher est cliquée.

Je ne sais pas quel est le bon moyen de faire fonctionner. Peut-être que le modèle React n'est-il pas le meilleur pour modéliser ce genre d'interation? Que puis-je faire?

Merci d'avance

Dans votre fonction de render , la portée de this fonction de mappage des checks est différente du render , qui est la portée dont vous avez besoin pour __changeSelection , de sorte que this.__changeSelection ne localisera pas une propriété __changeSelection . Si vous ajoutez un .bind(this) à la fin de cette fonction de mappage, vous pouvez lier sa portée à la même this que le render :

 var checks = this.state.data.map(function(d) { return ( <div> <input type="checkbox" data-id={d.id} checked={d.selected} onChange={this.__changeSelection} /> {d.id} <br /> </div> ); }.bind(this)); 

Sur une note parallèle, je passe simplement l' id à la fonction de gestionnaire au lieu d'attribuer des attributs de données. Cela supprimera la nécessité de localiser cet élément dans votre gestionnaire:

 var checks = this.state.data.map(function(d) { return ( <div> <input type="checkbox" checked={d.selected} onChange={this.__changeSelection.bind(this, d.id)} /> {d.id} <br /> </div> ); }.bind(this)); 

Ensuite, mettez à jour votre fonction __changeSelection pour passer l' id tant que premier arg et supprimez la ligne de recherche d'attribut:

 __changeSelection: function(id) { var state = this.state.data.map(function(d) { return { id: d.id, selected: (d.id === id ? !d.selected : d.selected) }; }); this.setState({ data: state }); } 

Voici un exemple de tout cela, ainsi qu'un jsfiddle pour que vous puissiez l'essayer :

 /** @jsx React.DOM */ var Test = React.createClass({ getInitialState: function() { return { data: [ { id: 1, selected: false }, { id: 2, selected: false }, { id: 3, selected: false }, { id: 4, selected: false } ] }; }, render: function() { var checks = this.state.data.map(function(d) { return ( <div> <input type="checkbox" checked={d.selected} onChange={this.__changeSelection.bind(this, d.id)} /> {d.id} <br /> </div> ); }.bind(this)); return ( <form> <input type="checkbox" ref="globalSelector" onChange={this.__changeAllChecks} />Global selector <br /> {checks} </form> ); }, __changeSelection: function(id) { var state = this.state.data.map(function(d) { return { id: d.id, selected: (d.id === id ? !d.selected : d.selected) }; }); this.setState({ data: state }); }, __changeAllChecks: function() { var value = this.refs.globalSelector.getDOMNode().checked; var state = this.state.data.map(function(d) { return { id: d.id, selected: value }; }); this.setState({ data: state }); } }); React.renderComponent(<Test />, document.getElementById('content')); 

Si vous utilisez des cases à cocher, vous pouvez utiliser l'attribut checkedLink . Voici une autre implémentation possible, qui rend la case à cocher globale contrôlée (au lieu de ne pas être contrôlée dans les réponses actuelles):

JsFiddle

 var Test = React.createClass({ getInitialState: function() { return { globalCheckbox: false, data: [ { id: 1, selected: false }, { id: 2, selected: false }, { id: 3, selected: false }, { id: 4, selected: false } ] }; }, changeCheckForId: function(id,bool) { this.setState( { data: this.state.data.map(function(d) { var newSelected = (d.id === id ? bool : d.selected); return {id: d.id, selected: newSelected}; } )}); }, changeCheckForAll: function(bool) { this.setState({ globalCheckbox: true, data: this.state.data.map(function(d) { return {id: d.id, selected: bool}; }) }); }, linkCheckbox: function(d) { return { value: d.selected, requestChange: function(bool) { this.changeCheckForId(d.id,bool); }.bind(this) }; }, linkGlobalCheckbox: function() { return { value: this.state.globalCheckbox, requestChange: function(bool) { this.changeCheckForAll(bool); }.bind(this) }; }, render: function() { var checks = this.state.data.map(function(d) { return ( <div> <input key={d.id} type="checkbox" checkedLink={this.linkCheckbox(d)} /> {d.id} <br /> </div> ); }.bind(this)); return ( <form> <input type="checkbox" checkedLink={this.linkGlobalCheckbox()} />Global selector <br /> {checks} </form> ); }, }); 

Il est plus simple d'utiliser checkedLink=this.linkState("checkboxValue") avec LinkedStateMixin si l'état à muter n'est pas profondément imbriqué (comme c'est le cas dans cette question)

Edit : checkedLink et valueLink sont obsolètes, mais ont été recommencés dans les versions précédentes de React.