我已经实现了一个Modal组件,它在屏幕上显示了一个模态对话框。通常,模态将有条件地显示。我可以通过两种方式在渲染函数中执行此操作:
render(){
...
<Modal show={this.state.showModal}>
// something in modal
</Modal>
}
在Modal组件中,我使用this.props.show为自己添加一个不同的类。如果为false,则会添加display:none来隐藏模态。
另一种方式是这样的:
render(){
...
{ this.state.showModal &&
(<Modal>
// something in modal
</Modal>)
}
}
这使用showModal
来决定是否在渲染中添加模态。
我想弄清楚的是:
我认为对于哪种方式更好,可能没有一定的答案。也许这只是个人选择?
答案 0 :(得分:6)
您的第一个示例始终呈现模态,但使用CSS隐藏/显示它。
您的第二个示例仅在显示时将模态插入到DOM中,否则它根本不会显示在DOM中。
除非它是可见的(第二个例子),否则我不想渲染它,但我认为这两者都不重要。第二个例子现在也有更少的道具,因此Modal组件更简单。
答案 1 :(得分:4)
答案在于Modal组件的实现。我希望使用render
道具show
方法来正确优化标记。您应该优化它以在未显示时消除大部分标记。
<强>为什么吗 在Modal中实现优化简化了其使用,其他组件不必意识到/担心渲染它的成本。
编辑: 因为我们使用React,与dom标记的成本相比,在v-dom中使用虚拟模态组件的成本可以忽略不计。因此,即使你的其他组件最终在他们的v-dom中使用show = false来保持模态,也没关系。
答案 2 :(得分:3)
我也喜欢第二种方法。尽管React最大限度地减少了在DOM中使用其他元素的负面影响,但是不渲染不具备的元素始终是一个好习惯。我会扩展这个想法,并提取在单独的函数中显示/隐藏Modal的逻辑,并在渲染中调用它。
render: function(){
...
{this.renderModal()}
},
renderModal: function(){
...
{this.state.showModal && (<Modal />)}
}
这使您可以灵活地在单个位置添加其他条件,并使渲染功能保持较小且易于理解。
答案 3 :(得分:2)
我回答了与the best way of opening/closing modal
相关的类似问题从那以后,我花了很多时间在React上学习了一些课程。
我发现这种通用方法可以很好地处理模态:使用一个完全控制的“哑”组件,需要3个道具。
要回答关于两者之间差异的问题,IMO选项1提供了更清晰,更灵活的API,而选项2更简约。
使用选项1,您可以使用CSS 或从[{1}}返回null
来隐藏/显示。我建议返回<Modal>
因为模态内容将不会被呈现而不是渲染它们并通过CSS“隐藏”它们。
选项2强制采用有条理渲染的更详细的“JSX方式”,我认为在许多情况下这是合适的。但是我觉得模态的概念值得隐藏/显示是null
组件API的一部分(props / methods / etc ......)
为什么要传递<Modal>
道具/回调?
考虑到大多数模态都有UX,例如关闭事件,例如:按[ESC],单击“x”,单击模态外部等等...需要通知模式如何通过传递“关闭自身”在下面的示例中,close
道具/回调。
close
如果你想让模态管理自己的状态,你可以用一个稍微聪明的组件包装“哑”模态并使用refs和“公共组件方法”(虽然我发现坚持简化的方法通常会减少头痛和后悔;))
// The simple, fully controlled Modal component
const Modal = React.createClass({
render() {
const {
show, // Boolean - Is the modal visible?
close, // Function - The modal needs a function to "close itself"
children, // node - The contents of the modal
} = this.props;
return !show ? null : (
<div className="some-class-for-styling">
<a onClick={close}>x</a>
{children}
</div>
);
}
});
const UsesModal = React.createClass({
setEditing(editing) {
this.setState({editing});
},
render() {
// `editing` could come from anywhere.
// Could be derived from props,
// or managed locally as state, anywhere really....
const {editing} = this.state;
return (
<div>
<h1>Some Great Component</h1>
<a onClick={() => this.setEditing(true)}>Show Modal!</a>
<Modal show={editing} close={() => this.setEditing(false)}>
Some great modal content... show based on UsesModal.state.editing
</Modal>
</div>
);
}
});
有很多方法可以包含简单的const SmarterModal = React.createClass({
close() {
this.setState({show: false});
},
open() {
this.setState({show: true});
},
render() {
const {children} = this.props;
const {show} = this.state;
return (
<Modal show={show} close={this.close}>
{children}
</Modal>
);
}
});
const UsesSmarterModal = React.createClass({
render() {
return (
<div>
<h1>Some Great Component</h1>
<a onClick={() => this.refs.my_smarter_modal.open()}>Show Modal!</a>
<SmarterModal ref="my_smarter_modal">
Some great modal content... show based on SmarterModals own internal state
</SmarterModal>
</div>
);
}
});
,但我觉得它可以作为一个坚实的基础,数据流很好地允许计算/推导“是模态开放”从哪里最有意义的。这是我发现可以很好地工作的方法。
答案 4 :(得分:1)
这只是另一种方法,react if module:
var Node = require('react-if-comp');
...
var Test = React.createClass({
render: function() {
return <Node if={this.state.showModal}
then={<Modal>// something in modal</Modal>} />;
}
});
答案 5 :(得分:0)
看看https://github.com/fckt/react-layer-stack,它允许显示/隐藏在树的不同部分呈现的内容,但在逻辑上与顶级组件连接(允许同时使用它的变量) ):
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>)
// ...