Javascript 显示/隐藏 ReactJS 组件而不丢失其内部状态?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/27723226/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Show/Hide ReactJS components without losing their internal state?
提问by Brad Parks
I've been hiding/showing react components by not rendering them, for example:
我一直在通过不渲染来隐藏/显示反应组件,例如:
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>
);
}
but just say that the <Bio/>component has lots of internal state. Everytime I recreate the component, it loses it's internal state, and resets to it's original state.
但只是说<Bio/>组件有很多内部状态。每次我重新创建组件时,它都会失去它的内部状态,并重置为它的原始状态。
I know of course that I could store the data for it somewhere, and pass it in via props or just globally access it, but this data doesn't really need to live outside of the component. I could also hide/show components using CSS (display:none), but I'd prefer to hide/show them as above.
我当然知道我可以将数据存储在某个地方,并通过 props 将其传入或只是全局访问它,但这些数据并不真正需要存在于组件之外。我也可以使用 CSS ( display:none)隐藏/显示组件,但我更喜欢像上面那样隐藏/显示它们。
What's the best practice here?
这里的最佳做法是什么?
EDIT: Maybe a better way to state the problem is to use an example:
编辑:也许说明问题的更好方法是使用示例:
Ignore React, and assume you were just using a desktop app that had a configuration dialog with a Tab component called A, which has 2 tabs, named 1 and 2.
忽略 React,并假设您只是在使用一个桌面应用程序,该应用程序有一个配置对话框,其中包含一个名为 A 的 Tab 组件,该组件有 2 个选项卡,分别命名为 1 和 2。
Say that tab A.1 has an email text field and you fill in your email address. Then you click on Tab A.2 for a second, then click back to Tab A.1. What's happened? Your email address wouldn't be there anymore, it would've been reset to nothing because the internal state wasn't stored anywhere.
假设选项卡 A.1 有一个电子邮件文本字段,并且您填写了您的电子邮件地址。然后单击选项卡 A.2 一秒钟,然后单击返回选项卡 A.1。发生了什么?你的电子邮件地址将不再存在,它会被重置为空,因为内部状态没有存储在任何地方。
Internalizing the state works as suggested in one of the answers below, but only for the component and it's immediate children. If you had components arbitrarily nested in other components, say Tabs in Tabs in Tabs, the only way for them to keep their internal state around is to either externalize it somewhere, or use the display:noneapproach which actually keeps all the child components around at all times.
按照以下答案之一的建议将状态内部化,但仅适用于组件及其直接子组件。如果您将组件任意嵌套在其他组件中,例如 Tabs in Tabs 中的 Tabs,它们保持内部状态的唯一方法是将其外部化在某处,或者使用display:none实际上始终保持所有子组件的方法.
It just seems to me that this type of data isn't data you want dirtying up your app state... or even want to even have to think about. It seems like data you should be able to control at a parent component level, and choose to either keep or discard, without using the display:noneapproach and without concerning yourself with details on how it's stored.
在我看来,这种类型的数据不是你想要弄脏你的应用程序状态的数据……甚至不想考虑。看起来您应该能够在父组件级别控制数据,并选择保留或丢弃,而无需使用该display:none方法,也无需关心有关其存储方式的详细信息。
采纳答案by Colin Ramsay
One option would be to move the conditional inside the component itself:
一种选择是在组件本身内部移动条件:
Bio = React.createClass({
render: function() {
if(this.props.show) {
return <p>bio comp</p>
} else {
return null;
}
}
});
<Bio show={isBioPage} />
Whether this is "best practise" or not probably depends on the exact situation.
这是否是“最佳实践”可能取决于具体情况。
回答by osamu
Unfortunately, style={{display: 'none'}}trick only works on normal DOM element, not React component. I have to wrap component inside a div. So I don't have to cascade the state to subcomponent.
不幸的是,style={{display: 'none'}}trick 只适用于普通的 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>
回答by nilgun
Looks like official documentation suggestshiding stateful children with style={{display: 'none'}}
看起来官方文档建议隐藏有状态的孩子style={{display: 'none'}}
回答by fckt
The fundamental problem here is that in React you're only allowed to mount component to its parent, which is not always the desired behavior. But how to address this issue?
这里的基本问题是,在 React 中,您只允许将组件挂载到其父级,这并不总是所需的行为。但是如何解决这个问题呢?
I propose the solution, addressed to fix this issue. More detailed problem definition, src and examples can be found here: https://github.com/fckt/react-layer-stack#rationale
我提出了解决方案,旨在解决这个问题。更详细的问题定义、源代码和示例可以在这里找到:https: //github.com/fckt/react-layer-stack#rationale
Rationale
react/react-domcomes comes with 2 basic assumptions/ideas:
- every UI is hierarchical naturally. This why we have the idea of
componentswhich wrap each otherreact-dommounts (physically) child component to its parent DOM node by defaultThe problem is that sometimes the second property isn't what you want in your case. Sometimes you want to mount your component into different physical DOM node and hold logical connection between parent and child at the same time.
Canonical example is Tooltip-like component: at some point of development process you could find that you need to add some description for your
UI element: it'll render in fixed layer and should know its coordinates (which are thatUI elementcoord or mouse coords) and at the same time it needs information whether it needs to be shown right now or not, its content and some context from parent components. This example shows that sometimes logical hierarchy isn't match with the physical DOM hierarchy.
基本原理
react/react-dom带有 2 个基本假设/想法:
- 每个 UI 都是自然分层的。这就是为什么我们有
components相互包裹的想法react-dom默认情况下将子组件(物理上)挂载到其父 DOM 节点问题是有时第二个属性不是你想要的。有时你想将你的组件挂载到不同的物理 DOM 节点,同时保持父子节点之间的逻辑连接。
典型的例子就是工具提示状的部分:在开发过程中的某些时候,你会发现,你需要添加一些说明对你的
UI element:它会在固定层渲染和应该知道它的坐标(这是UI element坐标或鼠标coords)使用,并在同时它需要信息是否需要立即显示,它的内容和来自父组件的一些上下文。此示例显示有时逻辑层次结构与物理 DOM 层次结构不匹配。
Take a look at https://github.com/fckt/react-layer-stack/blob/master/README.md#real-world-usage-exampleto see the concrete example which is answer to your question (take a look at the "use" property):
看看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>)
// ...

