2015-09-04 59 views
2

我有一个组件,它包括在像这样ReactJS另一个组件:ReactJS:是否有可能在其子组件中包含父组件?

var Child = require('Child'); 

var Parent = React.createClass({ 
    render: function() { 
    return (
     <div> 
     <Child key={someKey} data={someData} /> 
     </div> 
    ); 
    },  
}); 

module.exports = Parent; 

然后在我的子组件我想再次既包括父母和孩子。有点像嵌套div在彼此。

代码下面的子组件:

var Parent = require('Parent'); 

var Child = React.createClass({ 
    render: function() { 
    return (
     <div> 
     <Parent key={someOtherKey} data={someOtherData} /> 
     </div> 
    ); 
    } 
}); 

module.exports = Child; 

虽然我得到了以下错误:Uncaught TypeError: e.toUpperCase is not a function

这种行为是允许的反应是?如果不是,它应该如何构建?

谢谢!

回答

0

第一个问题是,你不能两个模块导入到各其他。第二个问题是你需要检查是否要创建第二个父对象,否则你会得到一个无限循环。事情是这样的:

var Child = require('Child'); 

var Parent = React.createClass({ 
    render: function() { 
    return (
     <div> 
     <Child key={someKey} data={someData} /> 
     </div> 
    ); 
    },  
}); 

module.exports = Parent; 

然后:

var Child = React.createClass({ 
    render: function() { 
    var parent = nil; 
    if ({hasNestedParent}) { 
     var Parent = require('Parent'); 
     parent = (
      <Parent key={someOtherKey} data={someOtherData} /> 
     ); 
    } 
    return (
     <div>{parent}</div> 
    ); 
    } 
}); 

module.exports = Child; 

注意,除非它需要的Parent模块不是孩子模块中imorted。

2

首先,您在代码中有一个循环依赖关系,ParentChild都需要对方。

为了避免无限循环需要模块时,模块CommonJS的作用是这样的:

Parent.js需要Child.js,当Child组件调用require('Parent'),的Parent.js导出的值是一个空对象。所以你得到错误e.toUpperCase is not a function,因为eParent)是一个空对象。

您应该module.exports语句后要求:

var Parent = React.createClass({ 
    render: function() { 
    return (
     <div> 
     <Child key={someKey} data={someData} /> 
     </div> 
    ); 
    },  
}); 

module.exports = Parent; 

var Child = require('Child'); 

但事件是否能解决循环依赖,我不明白你想达到什么样的,它实际上是一个无限循环。

+0

我知道OP正在创建类似于嵌套树视图的东西:一个文件夹包含一个文件列表,一个文件可以是另一个文件夹。 – mik01aj

+0

据我所知,我从来没有使用NPM/Browserify使用循环依赖的麻烦。 2个文件可以要求对方没有? –

+2

@SebastienLorber,因为Node和其他CommonJS模块加载程序通过“冻结”模块的状态来处理循环依赖关系,所以不会出现任何错误消息,从而产生空对象,但不会出错。这可能会导致很难检测到错误,例如“foo.barFunction不是函数”。 – Pcriulan

0

这是一个递归模式,getTreeNode作为共享元素。

import React, {Component} from 'react'; 
    import lodash from 'lodash'; 

    var TreeRootSty = {lineHeight: '120%'} 
    var liSty = {listStyleType: 'none'}; 
    var ulSty = {height: 'inherit', WebkitPaddingStart: '16px'}; 
    var ulStyle = {height: 'inherit', WebkitPaddingStart: '16px'}; 
    var iconSty = {marginRight: '10px', width: '16px'}; 
    var titleSty = {color: '#afac87', marginTop: '2px'}; 

    var nottogglable = { 
     color: '#FFF', 
     cursor: 'pointer', 
     margin: '0 0 0 .8em' 
    }; 

    var togglable = { 
     color: '#815C7C', 
     cursor: 'pointer', 
     margin: '0' 
    }; 

    var options = {}; 

    var getTreeNode = function(child, index) { 
     return <li key={index} style={liSty}><JTreeViewNode node={child} iconClick={this.props.iconClick} titleClick={this.props.titleClick} /></li>; 
    }; 

    class JTreeViewNodeRender extends Component { 
     binder(...methods) { methods.forEach((method) => this[method] = this[method].bind(this)); } 

     render() { 
      var childNodes; 
      var pSty = nottogglable; 
      if (lodash.has(this.props.node, 'children') && this.props.node.children.length > 0) { 
       childNodes = this.props.node.children.map(getTreeNode, this); 

       titleSty.color = this.props.node.selected ? '#7BB53B' : '#AF90A5'; 
      } else { 
       titleSty.color = this.props.node.selected ? '#b58900' : '#afac87'; 
      } 

      var isClosed = true; 
      if (lodash.has(this.props.node, 'closed')) isClosed = this.props.node.closed; 
      ulStyle.display = isClosed ? 'none' : 'inline-block'; 
      var props = this.props; 
      var iconType = lodash.get(props, options.typeName); 
      if (iconType == options.icon.sun) iconSty.background = "url('./img/sun.ico') 0/16px no-repeat !important"; 
      else if (iconType == options.icon.leaf) iconSty.background = "url('./img/leaf.ico') 0/16px no-repeat !important"; 
      else if (iconType == options.icon.snow) iconSty.background = "url('./img/snow.ico') 0/16px no-repeat !important"; 
      else iconSty.background = "url('./img/sun.ico') 0/16px no-repeat !important"; 

      return (
       <div id='TreeNode'> 
        <div id='pSty' style={pSty} className='FlexBox'> 
         <div id='iconSty' onClick={this.iconHandler} style={iconSty}>&nbsp;</div> 
         <div id='titleSty' onClick={this.clickHandler} style={titleSty} >{this.props.node.title}</div> 
        </div> 
        <ul id='ulStyle' style={ulStyle}> 
         {childNodes} 
        </ul> 
       </div> 
      ); 
     } 
    } 

    class JTreeViewNode extends JTreeViewNodeRender { 
     constructor() { 
      super(); 
      this.binder('clickHandler', 'iconHandler'); 
     } 
     iconHandler() { 
      if (lodash.has(this.props.node, 'children') && this.props.node.children.length > 0) { 
       this.props.iconClick(this.props.node); 
      } else { 
       this.clickHandler(); 
      } 
     } 
     clickHandler() { this.props.titleClick(this.props.node); } 
    } 

    class JTreeViewRender extends Component { 
     render() { 
      options = this.props.options; 
      var childNodes = this.props.data.map(getTreeNode, this); 
      return (
       <div id='TreeRootSty' style={TreeRootSty}> 
        <ul id='ulSty' style={ulSty}> 
          {childNodes} 
        </ul> 
       </div> 
      ); 
     } 
    } 

    export default class JTreeView extends JTreeViewRender {} 
0

你想要做什么是好的,但你必须照顾不创造一个无限递归,所以你需要一个停止条件。

这里是一个JsFiddle可执行例如

function getOffset(depth) { 
    var prefix = ""; 
    for (var i=0;i<depth;i++) { 
     prefix = prefix + "-"; 
    } 
    return prefix; 
} 

var Parent = React.createClass({ 
    render: function() { 
     var offset = getOffset(this.props.depth); 
     return <div>{offset}Parent=[<Child depth={this.props.depth}/>{offset}]</div>; 
    } 
}); 


var Child = React.createClass({ 
    render: function() { 
     if (this.props.depth >= 5) { 
      return false; 
     } 
     var newDepth = this.props.depth +1; 
     var offset = getOffset(this.props.depth); 
     return <div>{offset}Child=(<Parent depth={newDepth}/>{offset})</div>; 
    } 
}); 

React.render(<Parent depth={0} />, document.body); 

输出是

Parent=[ 
Child=(
-Parent=[ 
-Child=(
--Parent=[ 
--Child=(
---Parent=[ 
---Child=(
----Parent=[ 
----Child=(
-----Parent=[-----] 
----) 
----] 
---) 
---] 
--) 
--] 
-) 
-] 
) 
] 

这是有趣的:)

+0

感谢分享! – Ismailp