【问题标题】:Correct way to reference children in reactjs在 reactjs 中引用子项的正确方法
【发布时间】:2014-04-09 00:30:27
【问题描述】:

我正在研究 facebook 的 react.js,发现它到目前为止非常酷。我尝试制作一个简单的文件夹结构,您可以在其中打开和关闭每个文件夹。 我的结构是这样的

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

单击标题会导致文件夹隐藏/显示其内容。这很容易通过国家来完成。

但现在我想要多个文件夹和一个“全部切换”按钮。如何在不造成混乱的情况下获得切换所有孩子的按钮?我使用 refs 来解决它们,但我认为这是一种不好的做法,因为 the Documentation 指出:

...您的第一个倾向通常是尝试使用 refs 在您的应用中“让事情发生”...

...考虑在组件层次结构中应该拥有状态的位置。通常,很明显“拥有”该状态的适当位置位于层次结构中的更高级别。

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

PS(奖金问题): 通过不渲染它(就像在小提琴中所做的那样)隐藏内容更好,或者只是添加一个'display:none;'样式标签?

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    在 reactjs 中引用子项的正确方法 -> 不要引用子项来查询其状态。如果您需要从父级查询该状态,则将该状态放入父级并将该状态作为道具注入子级。

    这是您的代码重做: 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 组件可以简单地用于渲染文件夹,但不能用于管理文件夹的状态,或者在您的全局 toggleAll 操作中,您必须“查询”子组件以了解它们的状态。


    PS(额外问题):我认为不渲染未显示的内容更优雅。但出于性能原因,如果隐藏/显示状态频繁变化,使用display : none; 可能会更好:它会产生相同的视觉效果,但 DOM 差异会更轻。除非您发现不渲染隐藏元素存在性能问题,否则不要对此进行优化。

    【讨论】:

    • 感谢您的回答!我在怀疑这个。我只是认为将切换状态保存在文件夹本身会很好,因为我认为它属于那里。但你是对的,嵌套所有状态然后让它们交互似乎是一个糟糕的概念。
    • @eyeballz 如果只有来自文件夹组件的事件可以更改此状态,则文件夹打开/关闭状态属于该文件夹。在您的示例中,toggleAll 事件不是来自文件夹组件,而是来自另一个。考虑“哪些组件可以改变哪些应用程序状态”是一个好主意。然后找到最近的公共父组件,并将状态放在这里,这样您就不必在任何地方查询子组件。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-02
    • 1970-01-01
    • 2019-04-12
    • 2019-07-28
    • 2010-10-30
    • 1970-01-01
    相关资源
    最近更新 更多