javascript - Highlighting one object at a time with React -


i'm pretty new both react , javascript, , i've started learning building simple collapsible menu. works expected, except can't figure out how highlight 1 item @ time. suspect onclick method , state has owned higher level class sectionitem, i'm stuck in how make work. first instinct iterate on items in menu every time clicked, , make sure other items switched active=false.

is right way think this? explain how states work in react in context, , how should implement here?

the entire code available here: menu on codepen.io

this code item want make highlightable. i've not yet been able implement 1 item should highlighted @ once.

var sectionitem = react.createclass({   handleclick: function(){     if(!this.state.active) {       this.setstate({         currentitem: this,         active: true,         class: "sectionitem active"});     }   },   getinitialstate: function(){      return {        active: false,        class: "sectionitem"      }   },   render: function() {     return (         <div classname={this.state.class} onclick={this.handleclick}>{this.props.title}</div>      );   } }); 

great start! let's walk through problems in code first.

separation of concerns

there's no need create entire nested structure inside top-most component. contrived:

for (i=0; < this.props.menuitems.length; i++) {   if(this.props.menuitems[i].section !== lastsection) {     var section = this.props.menuitems[i].section;     var items = [];     (j=0; j < this.props.menuitems.length; j++) {       if(this.props.menuitems[j].section == section) {         var itemname = this.props.menuitems[j].name;         items.push(<sectionitem title={itemname} key={itemname} />);       };     }     sections.push(<section title={section} items={items} key={section} />);     lastsection = section;   } } 

quite on contrary. should try , make each component responsible rendering of own piece of information. improve if first treated data. problem sections not nested. if, instead of this...

var menu_items = [   {section: "about", name: "hey", key: "hey", selected: true},   {section: "about", name: "no", key: "no", selected: false},   {section: "about", name: "way", key: "way", selected: false},   {section: "people", name: "cakewalk", key: "cakewalk", selected: false},   {section: "people", name: "george", key: "george", selected: false},   {section: "people", name: "adam", key: "adam", selected: false},   {section: "projects", name: "pirate raid", key: "pirate raid", selected: false},   {section: "projects", name: "goosehunt", key: "goosehunt", selected: false}, ]; 

we had this:

var sections = [   {     name: "about",      items: [       {name: "hey", key: "hey", selected: true},       {name: "no", key: "no", selected: false},       {name: "way", key: "way", selected: false}       ]   },{     name: "people",      items: [       {name: "cakewalk", key: "cakewalk", selected: false},       {name: "george", key: "george", selected: false},       {name: "adam", key: "adam", selected: false}     ]   },{     name: "projects",      items: [       {name: "pirate raid", key: "pirate raid", selected: false},       {name: "goosehunt", key: "goosehunt", selected: false}     ]   } ]; 

then simplify accordion quite bunch. render 1 section each section:

var accordion = react.createclass({     render: function() {     return (       <div classname="main">         {this.props.sections.map(function(section){           return <section key={section.name} section={section}/>         })}       </div>     );   } }); 

likewise, section , sectionitem become quite simpler.

var section = react.createclass({   handleclick: function(){     this.setstate({       open: !this.state.open,       class: this.state.open ? "section" : "section open"     });   },   getinitialstate: function(){      return {        open: false,        class: "section"      }   },   render: function() {     return (       <div classname={this.state.class}>         <div classname="sectionhead" onclick={this.handleclick}>{this.props.section.name}</div>         <div classname="articlewrap">           <div classname="article">             {this.props.section.items.map(function(item){               return <sectionitem key={item.name} item={item}/>             })}           </div>         </div>       </div>     );   } });  var sectionitem = react.createclass({   handleclick: function(){     this.setstate({       currentitem: this,       active: !this.state.active,       class: this.state.active ? "sectionitem" : "sectionitem active"     });   },   getinitialstate: function(){      return {        active: false,        class: "sectionitem"      }   },   render: function() {     return (         <div classname={this.state.class} onclick={this.handleclick}>{this.props.item.name}</div>      );   } }); 

propagating state changes

now, original question. in more complex application, benefit more robust flux. however, now, following techniques exposed in thinking in react should solve problem.

indeed, 1 way bring state of "what open" accordion component. need let parent know being clicked. can through callback passed prop.

so, accordion have opensection state, , onchildclick receives clicked section's name. needs pass onchildclick each section.

var accordion = react.createclass({   getinitialstate: function() {     return {       opensection: null     };   },    onchildclick: function(sectionname) {     this.setstate({       opensection: sectionname     });   },    render: function() {     return (       <div classname="main">         {this.props.sections.map(function(section){           return <section key={section.name}                    onchildclick={this.onchildclick}                   open={this.state.opensection===section.name}                    section={section}/>         }.bind(this))}       </div>     );   } }); 

and section calls function when clicked, passing in it's own name.

var section = react.createclass({   handleclick: function(){     this.props.onchildclick(this.props.section.name);   },    render: function() {     var classname = this.props.open ? "section open" : "section"     return (       <div classname={classname}>         <div classname="sectionhead" onclick={this.handleclick}>{this.props.section.name}</div>         <div classname="articlewrap">           <div classname="article">             {this.props.section.items.map(function(item){               return <sectionitem key={item.name} item={item}/>             })}           </div>         </div>       </div>     );   } }); 

you can extrapolate solution sectionitem problem.

the resulting codepen here: http://codepen.io/gadr90/pen/wamqxg?editors=001

good luck on learning react! on right path.


Comments

Popular posts from this blog

toolbar - How to add link to user registration inside toobar in admin joomla 3 custom component -

linux - disk space limitation when creating war file -

How to provide Authorization & Authentication using Asp.net, C#? -