显示/隐藏 ReactJS 组件而不会丢失其内部状态
Show/Hide ReactJS components without losing their internal state?
我一直在通过不渲染它们来隐藏/显示反应组件,例如:
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/>
组件有很多内部状态。每次重新创建组件时,它都会丢失其内部状态,并重置为原始状态。
我当然知道我可以将它的数据存储在某个地方,并通过 props 传递它或只是全局访问它,但这些数据实际上并不需要存在于组件之外。我也可以使用CSS(display:none
)隐藏/显示组件,但我更愿意像上面一样隐藏/显示它们。
这里的最佳实践是什么?
编辑:也许说明问题的更好方法是使用一个例子:
忽略 React,并假设您只是使用了一个桌面应用程序,该应用程序具有一个名为 A 的选项卡组件的配置对话框,该组件有 2 个选项卡,分别名为 1 和 2。
假设选项卡 A.1 有一个电子邮件文本字段,您填写了电子邮件地址。然后,单击选项卡 A.2 一秒钟,然后单击返回选项卡 A.1。发生了什么事?您的电子邮件地址将不再存在,它将被重置为空,因为内部状态未存储在任何地方。
按照以下答案之一中的建议,内部化状态,但仅适用于组件及其直接子项。如果你的组件任意嵌套在其他组件中,比如选项卡中的选项卡,它们保持内部状态的唯一方法是将其外部化到某个地方,或者使用实际上始终保留所有子组件的display:none
方法。
在我看来,这种类型的数据不是您想要弄脏应用程序状态的数据......甚至想甚至不得不考虑。似乎您应该能够在父组件级别控制数据,并选择保留或丢弃,而无需使用display:none
方法,也不关心有关如何存储的详细信息。
一种选择是在组件本身内移动条件:
Bio = React.createClass({
render: function() {
if(this.props.show) {
return <p>bio comp</p>
} else {
return null;
}
}
});
<Bio show={isBioPage} />
这是否是"最佳实践"可能取决于具体情况。
不幸的是,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>
看起来官方文档建议将有状态的孩子隐藏在style={{display: 'none'}}
这里的根本问题是,在 React 中,你只被允许将组件挂载到它的父级,这并不总是期望的行为。但是如何解决这个问题呢?
我提出了解决此问题的解决方案。更详细的问题定义、src 和示例可以在这里找到:https://github.com/fckt/react-layer-stack#rationale
理由
react
/react-dom
附带2个基本假设/想法:
- 每个 UI 都是自然分层的。这就是为什么我们有相互包裹的
components
的想法- 默认情况下,
react-dom
将(物理)子组件挂载到其父 DOM 节点问题是有时第二个属性不是你想要的 在你的情况下。有时您希望将组件装载到 不同的物理 DOM 节点和保持之间的逻辑连接 父母和孩子同时。
规范示例是类似工具提示的组件:在某个时候 开发过程你会发现你需要添加一些
UI element
的描述:它将以固定图层呈现,并且 应该知道它的坐标(UI element
坐标或 鼠标坐标),同时它需要信息是否 现在是否需要显示,其内容和一些上下文来自 父组件。此示例显示有时逻辑层次结构 与物理 DOM 层次结构不匹配。
看看 https://github.com/fckt/react-layer-stack/blob/master/README.md#real-world-usage-example 看看具体的例子,这是对你的问题的回答(看看"use"属性):
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>)
// ...
- 内部分区字体大小获胜'调整浏览器窗口大小时不会随媒体查询而更改
- 事件和状态
- AJAX错误状态代码500内部服务器错误
- 流星用户帐户 - 内部状态
- 显示/隐藏 ReactJS 组件而不会丢失其内部状态
- 无法加载资源:服务器在绑定功能中以状态 500(内部服务器错误)进行响应
- 为什么这个 HTML/JS 在更改内部 HTML 后会恢复到原始状态
- Angular ui路由器阻止指令内部的状态触发
- 如何根据链接内部状态更改列表项的颜色
- Ajax错误:加载资源失败:服务器响应状态为500(内部服务器错误)
- 在angular.js控制器中为应用的内部状态定义变量来显示/隐藏元素
- 使用状态"onEnter"触发控制器内部的一个函数;函数
- 加载资源失败:服务器响应状态为500(内部服务器错误)MVC JAVASCRIPT
- 如何访问Redux reducer内部的状态
- 如何对一个只改变内部状态的函数进行单元测试
- 我是否应该改变一个已承诺并已解决的值的内部状态
- 将可折叠的内部模态dos't保持打开状态
- React无状态组件-如何组织内部函数
- 将状态绑定到 React 中映射函数内部的条件语句
- 使用YouTube Iframe API内部的jquery插件来获取状态