簡體   English   中英

反應條件渲染模式

[英]React conditional render pattern

我已經實現了一個模態組件,在屏幕上顯示模式對話框。 通常,模態將有條件地顯示。 我可以通過兩種方式在render函數中執行此操作:

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. 還有另一種方法嗎?

編輯:似乎不同的人有不同的偏好。 對我來說,我更喜歡@ErikTheDeveloper所說的。 顯示/隱藏模態的功能應該保留在模態中,當我們不需要顯示模態時,我們可以在模態中返回null。

我想也許沒有一個答案,哪種方式更好。 也許這只是個人選擇?

您的第一個示例始終呈現模式,但使用CSS隱藏/顯示它。

您的第二個示例僅在顯示時將模式插入到DOM中,否則它根本不會顯示在DOM中。

我不想渲染它,除非它是可見的(第二個例子),但我認為無論如何都不重要。 第二個例子現在也有更少的道具,因此Modal組件更簡單。

答案在於Modal組件的實現。 我希望它的render方法是使用show prop來正確優化標記。 您應該優化它以在未顯示時消除大部分標記。

為什么? 在Modal中實現優化簡化了其使用,其他組件不必意識到/擔心渲染它的成本。

編輯:因為我們使用React,與dom標記的成本相比,在v-dom中使用虛擬模態組件的成本可以忽略不計。 因此,即使你的其他組件最終在他們的v-dom中使用show = false來保持Modal,也無關緊要。

我也喜歡第二種方法。 盡管React最大限度地減少了在DOM中使用其他元素的負面影響,但是不渲染不具備的元素始終是一個好習慣。 我會擴展這個想法,並提取在單獨的函數中顯示/隱藏Modal的邏輯,並在渲染中調用它。

render: function(){
   ...
   {this.renderModal()}
},
renderModal: function(){
    ...
    {this.state.showModal && (<Modal />)}
}

這使您可以靈活地在單個位置添加其他條件,並使渲染功能保持小巧且易於理解。

我回答了一個類似的問題,有關開啟/關閉模態的最佳方式

從那以后,我花了很多時間在React上學習了一些課程。

我發現這種通用的方法可以很好地處理模態:使用一個完全控制的“啞”組件,需要3個道具。

  • show:Boolean - 模態是否可見?
  • close:Function - 模態需要一個回調才能自行關閉
  • children:node - 模態的內容

有關受控組件的信息,請參閱React Docs


要回答關於兩者之間差異的問題,IMO選項1提供了更清晰,更靈活的API,而選項2更簡約。

使用選項1,您可以使用CSS <Modal>返回null來處理隱藏/顯示。 我建議返回null因為模態內容將不會被呈現而不是渲染它們並通過CSS“隱藏”它們。

選項2強制更有說服力的“JSX方式”有條件地渲染,我認為在許多情況下是合適的。 但是我覺得模態的概念值得隱藏/顯示是<Modal>組件API的一部分(props / methods / etc ......)


為什么傳遞close道具/回調?

考慮到大多數情態動詞都UX如關閉的事件,如:按[ESC],點擊“X”,點擊模式外,等...一個模式需要通過向下流過被告知如何“關閉自己” close我的例子中的道具/回調。


代碼示例

// 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>
    );
  }
});

如果你想讓模態管理自己的狀態,你可以用一個稍微聰明的組件包裝“啞”模態並使用refs和“公共組件方法”(雖然我發現堅持使用簡化的方法通常會減少頭痛和后悔;))

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>
    );
  }
});

有許多方法可以包含簡單的<Modal> ,但我覺得它可以作為一個堅實的基礎,數據流很好地允許計算/推導“從最有意義的地方開始模態”。 這是我發現很好地工作的方法。

這只是另一種方法, 如果模塊反應

var Node = require('react-if-comp');
...
var Test = React.createClass({
    render: function() {
        return <Node if={this.state.showModal}
                     then={<Modal>// something in modal</Modal>} />;
    }
});

看看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>)
// ...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM