Подтвердить что ты не робот

Реакция условного рисования

Я внедрил компонент Modal, который показывает модальный диалог на экране. Обычно модальное отображение будет условно. Есть два способа сделать это в функции рендеринга:

render(){
    ...
    <Modal show={this.state.showModal}>
        // something in modal
    </Modal>
}

В модульном компоненте я использую this.props.show для добавления к нему другого класса. Если это неверно, оно добавит отображение: none, чтобы скрыть модальный.

Другой способ:

render(){
    ...
    { this.state.showModal &&
        (<Modal>
            // something in modal
        </Modal>)
    }
}

В этом случае используется showModal, чтобы решить, добавлять или не добавлять Modal в render.

Что я хочу понять:

  • В чем разница между этими двумя способами?
  • Один из них лучше другого?
  • Есть ли другой способ сделать это?

EDIT: Кажется, что разные люди имеют разные предпочтения. Для меня лично я предпочитаю, что сказал @ErikTheDeveloper. Способность, которая отображает/скрывает Modal, должна оставаться внутри Modal, и когда нам не нужно показывать Modal, мы можем вернуть null в Modal.

Я думаю, может быть, нет определенного ответа, для чего лучше. Может быть, это просто личный выбор?

4b9b3361

Ответ 1

Я ответил на аналогичный вопрос некоторое время назад, касаясь лучшего способа открытия/закрытия модального

Я провел много времени с Реактивом с тех пор и изучил несколько уроков на этом пути.

Я нашел этот общий подход для работы с модалами: использование полностью контролируемого "немого" компонента, который занимает 3 реквизита.

  • show: Boolean - Является ли модальным видимым?
  • close: Функция. Модалю требуется обратный вызов, чтобы закрыть себя.
  • children: node - содержимое модального

См. React Docs для информации о Контролируемые компоненты


Чтобы ответить на ваш вопрос о различии между ними, это то, что вариант IMO 1 обеспечивает более чистый и гибкий API для работы, тогда как опция 2 более минималистична.

С помощью опции 1 вы можете позаботиться о скрытии/показе, используя CSS или, возвращающий null из <Modal>. Я бы рекомендовал вернуть null, так как модальное содержимое просто не будет отображаться против их рендеринга и "спрятать" их через CSS.

Вариант 2 заставляет более подробный "способ JSX" условного рендеринга, который, по моему мнению, уместен во многих случаях. Однако я чувствую, что концепция модальности заслуживает скрытия/показа, являющегося частью API компонентов <Modal> (реквизиты/методы/и т.д.)


Зачем пропускать close prop/callback?

Учитывая, что большинство модалов имеют UX, например, закрытие таких событий, как: нажатие [ESC], нажатие "x", щелчок вне модального и т.д. модальность должна быть проинформирована о том, как "закрыть себя" посредством передачи вниз close prop/callback в моих примерах ниже.


Примеры кода

// 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>, но я чувствую, что он служит прочной основой, и поток данных отлично воспроизводится, чтобы вычислять/выводить "является модальным открытым", откуда самый смысл. Это подход, который я нашел, чтобы работать хорошо.

Ответ 2

Ваш первый пример всегда отображает модальный, но использует CSS, чтобы скрыть/показать его.

Второй пример вставляет только модальный код в DOM при его показе, иначе он вообще не отображается в DOM.

Я предпочитаю не делать это вообще, если это не видно (второй пример), но я не думаю, что это имеет большое значение в любом случае. Второй пример также имеет меньше реквизитов, поэтому Модальный компонент проще.

Ответ 3

Ответ заключается в реализации модального компонента. Я бы ожидал, что метод render будет использовать show prop для правильной оптимизации разметки. Вы должны оптимизировать его, чтобы устранить большую часть разметки, когда она не отображается.

Почему? Внедрение оптимизации в Modal упрощает его использование, другие компоненты не должны знать/беспокоиться о затратах на его рендеринг.

EDIT: Поскольку мы используем React, стоимость наличия фиктивного модального компонента в v-dom пренебрежимо мала по сравнению со стоимостью его разметки dom. Поэтому, даже если ваши другие компоненты в конечном итоге сохраняют Modal с show = false в их v-dom, это не имеет значения.

Ответ 4

Я предпочитаю второй подход. Несмотря на то, что React минимизирует негативное влияние наличия дополнительных элементов в DOM, всегда бывает хорошей практикой не отображать элементы, которые не предназначены. Я хотел бы расширить это мышление и извлечь логику отображения/скрытия Modal в отдельной функции и вызвать его в render.

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

Это дает вам гибкость для добавления дополнительных условий в одном месте и делает вашу рендерную функцию малой и легко понятной.

Ответ 5

Это еще один способ сделать это, отредактировать, если модуль:

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

Ответ 6

Взгляните на 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>)
// ...