在 reactjs 中引用子项的正确方法
Posted
技术标签:
【中文标题】在 reactjs 中引用子项的正确方法【英文标题】:Correct way to reference children in reactjs 【发布时间】:2014-04-09 00:30:27 【问题描述】:我正在研究 facebook 的 react.js,发现它到目前为止非常酷。我尝试制作一个简单的文件夹结构,您可以在其中打开和关闭每个文件夹。 我的结构是这样的
<Folder>
<Header/>
<Content/>
</Folder>
单击标题会导致文件夹隐藏/显示其内容。这很容易通过国家来完成。
但现在我想要多个文件夹和一个“全部切换”按钮。如何在不造成混乱的情况下获得切换所有孩子的按钮?我使用 refs 来解决它们,但我认为这是一种不好的做法,因为 the Documentation 指出:
...您的第一个倾向通常是尝试使用 refs 在您的应用中“让事情发生”...
...考虑在组件层次结构中应该拥有状态的位置。通常,很明显“拥有”该状态的适当位置位于层次结构中的更高级别。
我创建了一个Fiddle 来演示整个事情。它正在工作,但我认为这不是一个很好的解决方案。
PS(奖金问题): 通过不渲染它(就像在小提琴中所做的那样)隐藏内容更好,或者只是添加一个'display:none;'样式标签?
【问题讨论】:
【参考方案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
事件不是来自文件夹组件,而是来自另一个。考虑“哪些组件可以改变哪些应用程序状态”是一个好主意。然后找到最近的公共父组件,并将状态放在这里,这样您就不必在任何地方查询子组件。以上是关于在 reactjs 中引用子项的正确方法的主要内容,如果未能解决你的问题,请参考以下文章
在reactjs功能组件中实现contextType的正确方法是什么?
对象作为 React 子对象无效。如果您打算渲染一组子项,请改用数组 - 错误 Solidity - React
ReactJS:React-Month-Picker错误:功能组件不能具有引用。您是要使用React.forwardRef()吗?