2014-03-06 30 views
1

我正在查看Facebook的react.js,发现它非常酷迄今。我试图做一个简单的文件夹结构,在那里你可以打开和关闭每个文件夹。 我的结构看起来像这样正确的方式来参考reactjs中的孩子

<Folder> <Header/> <Content/> </Folder>

点击在文件夹隐藏页眉结果/示出它的内容。这很容易通过国家来完成。

但现在我想拥有多个文件夹和“切换所有”按钮。我怎样才能让按钮切换所有的孩子而不会造成混乱?我用裁判来解决这些问题,但我认为这是一个不好的做法,为the Documentation状态:

...您的第一个倾向通常将是尝试用裁判来“使事情发生”,在您的应用程序...

...想想组件层次结构中的状态应该属于哪里。通常情况下,很显然,“拥有”该州的适当位置在层次结构中处于较高水平。

我创建了一个Fiddle来演示整个事情。它正在工作,但我不认为这是一个很好的解决方案。

PS(红利问题): 是不是更好地隐藏内容通过只是不渲染它(像在小提琴中完成),或者只是添加一个'display:none' styletag?

回答

2

引用儿童反应的正确方法 - >不要引用儿童来查询他们的状态。如果您需要从父项查询该状态,请将该状态置于父项中,并在子项中注入状态作为道具。

这里是你的代码返工: http://jsfiddle.net/t5fwn/7/

/** @jsx React.DOM */ 
var initialState = { 
    "folders": [ 
    { 
     "name": "folder1", 
      "open": false, 
      "files": [{ 
      "text": "content1 1" 
     }] 
    }, 
    { 
     "name": "folder2", 
      "open": false, 
      "files": [{ 
      "text": "content2 1" 
     }, { 
      "text": "content2 2" 
     }] 
    } 
    ] 
}; 

var Folder = React.createClass({ 

    render: function() { 
     var items = []; 
     if(this.props.folderData.open){ 
      this.props.folderData.files.forEach(function(file) { 
       items.push(<div className="itemBox">{file.text}</div>); 
      }); 
     } 
     return (
      <div className="items_directory"> 
       <div className="folder_header" onClick={this.props.onFolderClick}>{this.props.folderData.name}</div> 
       <div className="folder_content"> 
        {items} 
       </div> 
      </div> 
     ); 
    } 
}); 

var FoldersManager = React.createClass({ 

    getInitialState: function() { 
     return this.props.initialState; 
    }, 

    render: function(){ 
     var self = this; 
     var folderComponents = this.state.folders.map(function(folder,folderIndex) { 
      var onFolderClick = function() { 
       self.toggleFolder(folderIndex); 
      }; 
      return <Folder folderData={folder} onFolderClick={onFolderClick}/>; 
     }); 
     return (
      <div> 
       <button onClick={this.toggleAll}>Toggle All</button> 
       <div> 
        {folderComponents} 
       </div> 
      </div> 
     ); 
    }, 

    toggleFolder: function(folderIndex) { 
      var newState = this.state; 
      newState.folders[folderIndex].open = !newState.folders[folderIndex].open; 
      this.setState(newState); 
    }, 

    toggleAll: function(){ 
     var newState = this.state; 
     var newOpenToSet = this.isAllFoldersOpen() ? false : true; 
     newState.folders.forEach(function(folder) { 
      folder.open = newOpenToSet; 
     }); 
     this.setState(newState); 
    }, 

    isAllFoldersOpen: function() { 
     return this.countFoldersOpen() == this.state.folders.length; 
    }, 

    countFoldersOpen: function() { 
     var i = 0; 
     this.state.folders.forEach(function(folder) { 
     if (folder.open) i++; 
     }); 
     return i; 
    } 

}); 

React.renderComponent(<FoldersManager initialState={initialState} />, document.body); 

最好是具有某种可处理所有文件夹的状态打开/关闭管理器组件。 Folder组件可以简单地用于渲染文件夹,但不用于管理文件夹的状态,或者在您的全局操作中,您将不得不“查询”子组件以了解其状态。


PS(奖金问题):我认为这是更优雅不渲染不显示的内容。但出于性能方面的原因,如果隐藏/显示状态频繁更改,最好使用display : none;:它会产生相同的视觉效果,但DOM差异会更小。除非您看到不呈现隐藏元素的性能问题,否则不要优化它。

+0

感谢您的回答!我怀疑这一点。我只是认为将切换状态保存到文件夹本身会很好,因为我认为它属于那里。但你是对的,嵌套所有的州,然后让他们互动似乎是一个坏概念。 – eyeballz

+0

@eyeballz如果只有来自文件夹组件的事件可以更改此状态,则文件夹打开/关闭状态属于该文件夹。在你的例子中'toggleAll'事件不是来自文件夹组件,而是来自另一个。认为“哪些组件可以改变哪个应用程序状态”是一个好主意。然后,您可以找到最近的共同父母,并将此状态置于此处,以便您不必在任何地方查询儿童组件。 –