反应条件渲染模式

时间:2015-12-18 03:36:33

标签: javascript reactjs

我已经实现了一个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来决定是否在渲染中添加模态。

我想弄清楚的是:

  1. 这两种方式有什么不同?
  2. 其中一个比另一个好吗?
  3. 还有其他办法吗?
  4. 编辑:似乎不同的人有不同的偏好。对我来说,我更喜欢@ErikTheDeveloper所说的。显示/隐藏模态的功能应保留在模态中,当我们不需要显示模态时,我们可以在模态中返回null。

    我认为对于哪种方式更好,可能没有一定的答案。也许这只是个人选择?

6 个答案:

答案 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个道具。

  • show:Boolean - 模态是否可见?
  • close:Function - 模态需要回调才能自行关闭
  • children:node - 模态的内容

有关Controlled Components

的信息,请参阅React Docs

要回答关于两者之间差异的问题,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>)
// ...