为什么组件在 ReactJS 中只能返回一个节点?(有根本原因吗?) [英] Why can components only return one node in ReactJS? (Is there a fundamental reason?)
问题描述
来自文档:
<块引用>最大 JSX 根节点数
目前,在组件的渲染中,您只能返回一个节点;如果你有一个 div 列表返回,您必须将组件包装在 div、span 或任何其他组件.
别忘了 JSX 会编译成普通的 js;返回两个函数并没有真正的语法意义.同样,不要放三元组中不止一个孩子.
上面的解释说当前",这表明一个组件可能返回一个函数,该函数导致两个节点而不是一个节点.这只是技术限制,还是融入了哲学?
我是如何想到这个问题的:我正试图使用 React 呈现 Bootstrap 菜单,而 Bootstrap 使用子选择器,而不是后代选择器,这很有意义.
<小时>旁白:我是如何解决我的特定问题的:
我最感兴趣的是 React 的架构,但如果你好奇这就是我的情况.
目前在 Bootstrap 中,您可以制作下拉菜单:
<a class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="true">菜单 <span class="caret"></span></a><div id="macroMenu" class="react-component"><ul class="macroInsertion dropdown-menu" role="menu"><li><form class="navbar-form navbar-left" role="search"><div class="form-group"><input type="text" class="form-control search-filter" placeholder="Search"/>
</表单><li><a href="#">菜单 1</a><li><a href="#">菜单 2</a><li class="divider"></li><li><a href="#">菜单 3</a>
默认的 Bootstrap 样式表有像 .pull-right > .dropdown-menu 和 .open > .dropdown-menu 这样的选择器,如果你在容器和包含之间插入单个元素,它们就不起作用.这是有道理的,因为它可能更快,而且 Bootstrap 有时可能会处理双嵌套选择器,但它破坏了我们的系统,因为它在中间有 .react-component.
就我而言,我手动找出了 .react-component 破坏了什么,并创建了新样式以解决缺失的行为.
这是目前的技术限制.然而,有一些(随意的)谈论允许这样做:
var Foo = React.createClass({使成为(){return [<Bar/>, <Baz/>];}});var Quux = React.createClass({使成为(){返回<div><span/><Foo/></div>;}});
并且
将导致这种结构:
<跨度/><酒吧/><巴兹/>
这对于处理 HTML 中的一些僵化(表格、列表、标题)很有用,也适用于兄弟关系重要的样式(例如 display: inline-block
)或您无法控制的地方使用样式和直接子选择器(>
)或兄弟选择器(~
或 +
).
如果您确实遇到了其中一种情况,您很可能只是在实现渲染,因此使用实用程序函数而不是组件将是一个很好的解决方法.
var Foo = function(props){return [<Bar/>, <Baz/>];}var Quux = React.createClass({使成为(){return <div>{flatten( <span/>, Foo({}) )}</div>;}});//通常你从下划线或类似的地方得到这个var flatten = function(){ return Array.prototype.reduce.call(arguments, function(acc, x){ return acc.concat(x) }, []) };
From the docs:
Maximum Number of JSX Root Nodes
Currently, in a component's render, you can only return one node; if you have, say, a list of divs to return, you must wrap your components within a div, span or any other component.
Don't forget that JSX compiles into regular js; returning two functions doesn't really make syntactic sense. Likewise, don't put more than one child in a ternary.
The explanation above says "currently," which suggests that a component that could potentially return a function that results in two nodes instead of one. Is this just a technical limitation, or is this baked into the philosophy?
How I thought of this question: I'm in a situation where I'm trying to render a Bootstrap menu using React, and Bootstrap uses child selectors, instead of descendent selectors, which makes perfect sense.
Aside: How I solved my particular problem:
I'm mostly interested in the architecture of React, but in case you're curious this was my situation.
Currently in Bootstrap you can make a dropdown menu:
<li role="presentation" class="dropdown pull-right">
<a class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="true"> Menu <span class="caret"></span> </a>
<div id="macroMenu" class="react-component">
<ul class="macroInsertion dropdown-menu" role="menu">
<li>
<form class="navbar-form navbar-left" role="search">
<div class="form-group">
<input type="text" class="form-control search-filter" placeholder="Search" />
</div>
</form>
</li>
<li>
<a href="#">Menu 1</a>
</li>
<li>
<a href="#">Menu 2</a>
</li>
<li class="divider"></li>
<li>
<a href="#">Menu 3</a>
</li>
</ul>
</div>
</li>
The default Bootstrap stylesheet has selectors like .pull-right > .dropdown-menu and .open > .dropdown-menu though, which don't work if you insert a single element in between container and contained. This makes sense because it's presumably faster and Bootstrap may sometimes deal with double-nested selectors, but it broke our system to have .react-component in the middle.
In my case, I manually figured out what .react-component was breaking and made new styles to account for the missing behavior.
It's a technical limitation currently. However there has been some (casual) talk about allowing this:
var Foo = React.createClass({
render(){
return [<Bar />, <Baz />];
}
});
var Quux = React.createClass({
render(){
return <div><span /><Foo /></div>;
}
});
And <Quux />
would result in this structure:
<div>
<span />
<Bar />
<Baz />
</div>
This is useful to deal with some rigidity in HTML (tables, lists, head), and also for styling where siblings matter (e.g. display: inline-block
) or where you have no control over the styling and direct child (>
) or sibling selectors (~
or +
) are used.
If you do run into one of these cases, you're most likely just implementing render, so using a utility function instead of a component would be a good workaround.
var Foo = function(props){
return [<Bar />, <Baz />];
}
var Quux = React.createClass({
render(){
return <div>{flatten( <span />, Foo({}) )}</div>;
}
});
// usually you get this from underscore or similar
var flatten = function(){ return Array.prototype.reduce.call(arguments, function(acc, x){ return acc.concat(x) }, []) };
这篇关于为什么组件在 ReactJS 中只能返回一个节点?(有根本原因吗?)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!