繁体   English   中英

ReactJS:是否可以在其子组件中包含父组件?

[英]ReactJS: Is it possible to include a parent component in its child component?

我有一个组件,其中包含 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

React 中允许这种行为吗? 如果不是,它应该如何构建?

首先,您的代码中存在循环依赖关系, ParentChild都需要彼此。

为了在需要模块时避免无限循环,CommonJS 模块的行为如下:

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

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

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

module.exports = Parent;

var Child = require('Child');

但是如果这解决了循环依赖,我不明白你想要实现什么,它实际上是一个无限循环。

这是一个以 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 {}

您想要做的没问题,但您必须注意不要创建无限递归,因此您需要一个停止条件。

这是一个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=[-----]
----)
----]
---)
---]
--)
--]
-)
-]
)
]

这很好笑 :)

第一个问题是您不能将两个模块相互导入。 第二个问题是你需要检查是否创建第二个父对象,否则你会得到无限循环。 像这样的东西:

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模块。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM