草庐IT

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

coder 2024-07-23 原文

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

最佳答案

伟大的开始!让我们先解决一下代码中的一些问题。

关注点分离

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

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 中公开的技术应该可以解决你的问题。

的确,一种好方法是将“打开的内容”的状态带到 Accordion 组件中。您只需要让您的 parent 知道某些东西被点击了。我们可以通过作为 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 好运!您走在正确的道路上。

关于javascript - 使用 React 一次突出显示一个对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31280902/

有关javascript - 使用 React 一次突出显示一个对象的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  4. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  5. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  6. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  7. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  8. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  9. ruby-on-rails - 按天对 Mongoid 对象进行分组 - 2

    在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev

  10. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

随机推荐