使用React一次突出显示一个对象

时间:2015-07-07 23:06:23

标签: javascript menu onclick reactjs

我对React和Javascript都很陌生,我已经开始通过构建一个简单的可折叠菜单来学习它。它按预期工作,除了我无法弄清楚如何一次只突出显示一个项目。我怀疑onClick方法和状态必须由比sectionItem更高级别的类所拥有,但我真的陷入了如何使这项工作。我的第一直觉是每次点击某些内容时迭代菜单中的所有项目,并确保所有其他项目都切换为active = false。

这是考虑这个问题的正确方法吗?有人可以在这个背景下解释状态如何在React中工作,以及我应该如何在这里实现它?

整个代码可在此处获取:Menu on codepen.io

这是我想要突出显示的项目的代码。我还没有能够实现一次只突出显示一个项目。

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> 
    );
  }
});

1 个答案:

答案 0 :(得分:10)

好开始!让我们先在代码中解决一些问题。

关注点分离

无需在最顶层的组件中创建整个嵌套结构。这是非常人为的:

for (i=0; i < this.props.menuitems.length; i++) {
  if(this.props.menuitems[i].section !== lastSection) {
    var section = this.props.menuitems[i].section;
    var items = [];
    for (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;
  }
}

恰恰相反。您应该尝试让每个组件负责呈现他们自己的信息。如果我们首先处理您的数据,我们可以改进这一点问题是您的部分不是嵌套的。如果,而不是这个......

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},
];

我们有这个:

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}
    ]
  }
];

然后我们可以简化Accordion一堆。我们只为每个Section呈现一个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>
    );
  }
});

同样,Section和SectionItem变得相当简单。

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> 
    );
  }
});

传播状态变化

现在,问你原来的问题。在更复杂的应用程序中,您可以从像Flux这样更强大的东西中受益。但是,就目前而言,遵循Thinking in React中公开的技术可以解决您的问题。

确实,一个好的方法是带来你的状态&#34;什么是开放的&#34;到Accordion组件。您只需要让您的父母知道正在点击某些内容。我们可以通过作为prop传递的回调来实现。

因此,Accordion可以有一个openSection州,一个onChildClick可以获得点击的部分名称。它需要将onChildClick传递给每个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>
    );
  }
});

Section只需在点击时调用此功能,并传入其自己的名称。

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>
    );
  }
});

您可以将此解决方案推断为SectionItem问题。

生成的代码集在此处:http://codepen.io/gadr90/pen/wamQXG?editors=001

学习React祝你好运!你是在正确的道路上。