reactjs - How do I set state of sibling components easily in React? -


i have got beginnings of clickable list component serve drive select element. can see below, onclick of listitem, i'm passing state of child element (listitem in case) parents (selectablelist, , customselect component). working fine. however, change state of sibling components (the other listitems) can toggle selected states when 1 of listitems clicked.

at moment, i'm using document.queryselectorall('ul.cs-select li) grab elements , change class selected when doesn't match index of clicked listitem. works - extent. however, after few clicks, state of component has not been updated react (only client side js), , things start break down. change this.state.isselected of sibling list items, , use state refresh selectablelist component. offer better alternative i've written below?

var react = require('react'); var selectbox = require('./select-box');  var listitem = react.createclass({     getinitialstate: function() {         return {             isselected: false         };     },      toggleselected: function () {         if (this.state.isselected == true) {             this.setstate({                 isselected: false             })         } else {             this.setstate({                 isselected: true             })         }     },      handleclick: function(listitem) {         this.toggleselected();         this.props.onlistitemchange(listitem.props.value);          var unboundforeach = array.prototype.foreach,             foreach = function.prototype.call.bind(unboundforeach);          foreach(document.queryselectorall('ul.cs-select li'), function (el) {              // below trying              // make sure when user clicks on list             // item in selectablelist, *other*             // list items class="selected" removed.             // works first time move through              // list clicking other items, then, on second             // pass through, starts fail, requiring *two clicks* before             // list item selected again.             // maybe there's better more "reactive" method of doing this?              if (el.dataset.index != listitem.props.index && el.classlist.contains('selected') ) {                 el.classlist.remove('selected');             }         });     },      render: function() {         return (             <li ref={"listsel"+this.props.key}                 data-value={this.props.value}                 data-index={this.props.index}                 classname={this.state.isselected == true ? 'selected' : '' }                  onclick={this.handleclick.bind(null, this)}>                 {this.props.content}             </li>         );     } });  var selectablelist = react.createclass({      render: function() {          var listitems = this.props.options.map(function(opt, index) {             return <listitem key={index} index={index}                          value={opt.value} content={opt.label}                         onlistitemchange={this.props.onlistitemchange.bind(null, index)} />;         }, this);          return <ul classname="cs-select">{ listitems }</ul>;     }  })  var customselect = react.createclass({      getinitialstate: function () {         return {             selectedoption: ''         }     },      handlelistitemchange: function(listindex, listitem) {         this.setstate({             selectedoption: listitem.props.value         })     },      render: function () {          var options = [{value:"one", label: "one"},{value:"two", label: "two"},{value:"three", label: "three"}];          return (             <div classname="group">                 <div classname="cs-select">                     <selectablelist options={options}                          onlistitemchange={this.handlelistitemchange} />                     <selectbox classname="cs-select"                          initialvalue={this.state.selectedoption}                          fieldname="custom-select" options={options}/>                 </div>             </div>         )     }  })  module.exports = customselect; 

the parent component should pass callback children, , each child trigger callback when state changes. hold of state in parent, using single point of truth, , pass "selected" value down each child prop.

in case, child this:

var child = react.createclass({     ontoggle: function() {         this.props.ontoggle(this.props.id, !this.props.selected);     },      render: function() {         return <button onclick={this.ontoggle}>toggle {this.props.label} - {this.props.selected ? 'selected!' : ''}!</button>;     } }); 

it has no state, fires ontoggle callback when clicked. parent this:

var parent = react.createclass({     getinitialstate: function() {         return {             selections: []         };     },     onchildtoggle: function(id, selected) {         var selections = this.state.selections;          selections[id] = selected;          this.setstate({             selections: selections         });     },      buildchildren: function(dataitem) {         return <child             id={dataitem.id}             label={dataitem.label}             selected={this.state.selections[dataitem.id]}             ontoggle={this.onchildtoggle} />     },      render: function() {         return <div>{this.props.data.map(this.buildchildren)}</div>     } }); 

it holds array of selections in state , when handles callback child, uses setstate re-render children passing state down in selected prop each child.

you can see working example of here:

https://jsfiddle.net/fth25erj/


Comments

Popular posts from this blog

javascript - Google App Script ContentService downloadAsFile not working -

javascript - Function overwritting -

php - Find a regex to take part of Email -