我一直在隐藏/显示反应组件而不渲染它们,例如:
render: function() {
var partial;
if (this.state.currentPage === 'home') {
partial = <Home />;
} else if (this.state.currentPage === 'bio') {
partial = <Bio />;
} else {
partial = <h1>Not found</h1>
}
return (
<div>
<div>I am a menu that stays here</div>
<a href="#/home">Home</a> <a href="#/bio">Bio</a>
{partial}
</div>
);
}
但只是说<Bio/>
组件有很多内部状态。每次我重新创建组件时,它都会丢失它的内部状态,并重置为它的原始状态。
我当然知道我可以在某处存储数据,并通过道具传递或者只是全局访问它,但这些数据并不需要在组件之外生存。我也可以使用CSS(display:none
)隐藏/显示组件,但我更喜欢隐藏/显示它们。
这里的最佳做法是什么?
编辑:也许更好地说明问题的方法是使用示例:
忽略React,并假设您刚刚使用的桌面应用程序具有名为A的Tab组件的配置对话框,该组件具有2个选项卡,名为1和2.
假设标签A.1有一个电子邮件文本字段,您可以填写您的电子邮件地址。然后单击Tab A.2一秒钟,然后单击返回选项卡A.1。发生了什么?您的电子邮件地址将不再存在,它将被重置为空,因为内部状态未存储在任何地方。
内部化状态的工作原理如下面的一个答案所示,但仅适用于组件及其直接子项。如果您在其他组件中任意嵌套了组件,比如选项卡中选项卡中的选项卡,那么它们保持内部状态的唯一方法是将其外部化,或者使用实际保留所有子项的display:none
方法周围的组件。
在我看来,这种类型的数据不是您想要弄乱应用程序状态的数据......甚至想要甚至不得不考虑。看起来您应该能够在父组件级别控制数据,并选择保留或丢弃,而不使用display:none
方法,并且不关心自己如何存储的详细信息。
答案 0 :(得分:10)
一种选择是在组件内部移动条件:
Bio = React.createClass({
render: function() {
if(this.props.show) {
return <p>bio comp</p>
} else {
return null;
}
}
});
<Bio show={isBioPage} />
这是否是“最佳实践”,可能取决于具体情况。
答案 1 :(得分:5)
不幸的是,style={{display: 'none'}}
技巧仅适用于普通的DOM元素,而不适用于React组件。我必须在div中包装组件。所以我不必将状态级联到子组件。
<div className="content">
<div className={this.state.curTab == 'securities' ? 'active' : ''}>
<Securities />
</div>
<div className={this.state.curTab == 'plugins' ? 'active' : ''}>
<Plugins />
</div>
</div>
答案 2 :(得分:3)
看起来official documentation suggests隐藏有状态的孩子style={{display: 'none'}}
答案 3 :(得分:2)
这里的根本问题是,在React中,您只能将组件安装到其父组件,这并不总是所需的行为。但是如何解决这个问题?
我提出解决方案,以解决此问题。更详细的问题定义,src和示例可以在这里找到:https://github.com/fckt/react-layer-stack#rationale
原理
react
/react-dom
附带了两个基本假设/想法:
- 每个UI都是自然分层的。这就是为什么我们有
components
相互包装的想法react-dom
默认情况下(物理上)将子组件安装到其父DOM节点问题是有时第二个属性不是你想要的 在你的情况下。有时您想要将组件安装到 不同的物理DOM节点和之间保持逻辑连接 父母和孩子在同一时间。
典型的例子是类似Tooltip的组件:在某些时候 开发过程你可以发现你需要添加一些 您
UI element
的说明:它将在固定图层中呈现 应该知道它的坐标(UI element
坐标或坐标 鼠标coords),同时它需要信息是否 需要立即显示或不显示,其内容和一些背景 父组件。此示例显示有时是逻辑层次结构 与物理DOM层次结构不匹配。
查看https://github.com/fckt/react-layer-stack/blob/master/README.md#real-world-usage-example以查看回答您问题的具体示例(请查看“使用”属性):
import { Layer, LayerContext } from 'react-layer-stack'
// ... for each `object` in array of `objects`
const modalId = 'DeleteObjectConfirmation' + objects[rowIndex].id
return (
<Cell {...props}>
// the layer definition. The content will show up in the LayerStackMountPoint when `show(modalId)` be fired in LayerContext
<Layer use={[objects[rowIndex], rowIndex]} id={modalId}> {({
hideMe, // alias for `hide(modalId)`
index } // useful to know to set zIndex, for example
, e) => // access to the arguments (click event data in this example)
<Modal onClick={ hideMe } zIndex={(index + 1) * 1000}>
<ConfirmationDialog
title={ 'Delete' }
message={ "You're about to delete to " + '"' + objects[rowIndex].name + '"' }
confirmButton={ <Button type="primary">DELETE</Button> }
onConfirm={ this.handleDeleteObject.bind(this, objects[rowIndex].name, hideMe) } // hide after confirmation
close={ hideMe } />
</Modal> }
</Layer>
// this is the toggle for Layer with `id === modalId` can be defined everywhere in the components tree
<LayerContext id={ modalId }> {({showMe}) => // showMe is alias for `show(modalId)`
<div style={styles.iconOverlay} onClick={ (e) => showMe(e) }> // additional arguments can be passed (like event)
<Icon type="trash" />
</div> }
</LayerContext>
</Cell>)
// ...