ReactJS: управление дочерним состоянием из дочернего и родительского

У меня довольно простая проблема, и я не уверен, как ее решить с помощью одного потока данных.

Скажите, что у вас есть ссылка в родительском, которая показывает модальный

В модальном режиме у вас есть "X", который закрывает его.

Я знаю, что могу изменить состояние модальности у родителя через реквизиты

// In the parent
<Modal display={this.state.showModal} />

// In the modal
<div className={this.props.display ? "show" : "hide"}>
  <a className="close">&times;</a>
  ...
</div>

И я знаю, как закрыть модальный, но не тот и другой. Не уверен, как сохранить состояние, которое является общим и контролируемым как родительским, так и дочерним модальным.

UPDATE

В попытке сохранить это как можно более модульным, я думаю, что метод React будет хранить логику open/close в модальной переменной.

var ParentThing = React.createClass({
  ...
  render (
    <Modal /> // How can I call this.open in the modal from here?
  )
});

var Modal = React.createClass({
  setInitialState: function() {
    return {
      display: false
    }
  },
  close: function() {
    this.setState({ display: false });
  },
  open: function() {
    this.setState({ display: true });
  },
  render: function() {
    return (
      <div className={this.state.display ? "show" : "hide"}>
        <a className="close" onClick={this.close}>&times;</a>
      </div>
    )
  }
});

Я видел этот метод, но, похоже, это немного больше, чем мне нужно делать здесь. Reactjs: как изменить дочернее состояние или реквизит от родителя?

Ответ 1

В React есть два способа справиться с такими вещами:

  • Сделать дочерний элемент "управляемым" так же, как ввод формы с атрибутами value и onChange, где владелец ввода управляет входом.
  • Сделать дочерний элемент "неконтролируемым" так же, как ввод формы без value.

Второй выбор кажется более быстрым, но, как и управление коллекцией входных данных форм в React, преимущество использования полностью контролируемых компонентов становится очевидным по мере построения сложности и необходимости полного описания вашего пользовательского интерфейса в любой момент и времени. (См. этот отличный ответ от FakeRainBrigand, если вам интересно, почему в большинстве случаев контролируемые компоненты лучше, чем неконтролируемые.)

Однако, как и входы формы, нет причин, по которым ваш компонент не может быть ни управляемым, ни бесконтрольным. Если пользователь передает свойство display и onClose, например ответ Austin Greco, у вас есть управляемый модальный, и родитель полностью решает, когда показывать или скрывать модально.

Если пользователь этого не делает, вы можете пропустить использование свойств и вместо этого делегировать во внутреннее состояние, управляемое общедоступными методами модального компонента:

var ParentThing = React.createClass({
  ...
  render: function() {
    return <Modal ref="modal" />;
  },

  handleSomeClick: function() {
    this.refs.modal.open();
  }
});

var Modal = React.createClass({
  setInitialState: function() {
    return {
      display: false
    }
  },
  close: function() {
    this.setState({ display: false });
  },
  open: function() {
    this.setState({ display: true });
  },
  render: function() {
    return (
      <div className={this.state.display ? "show" : "hide"}>
        <a className="close" onClick={this.close}>&times;</a>
      </div>
    )
  }
});

Если вам нравится идея управляемого компонента Modal, но вы не хотите делать все печатные команды, вы даже можете реализовать что-то вроде свойства valueLink для Modal, чтобы упростить этот шаблон.

var ParentThing = React.createClass({
  ...
  mixins: [React.addons.LinkedStateMixin],

  getInitialState: function() {
    return { showModal: false };
  },

  render: function() {
    return <Modal displayLink={this.linkState("showModal")} />;
  },

  handleSomeClick: function() {
    this.setState({showModal: true});
  }
});

var Modal = React.createClass({
  close: function() {
    this.props.displayLink.requestChange(false);
  },

  render: function() {
    return (
      <div className={this.props.displayLink.value? "show" : "hide"}>
        <a className="close" onClick={this.close}>&times;</a>
      </div>
    )
  }
});

(см. мое сообщение в блоге о создании пользовательских компонентов, которые работают с linkState/valueLink для получения дополнительной информации).

Итак, теперь вы получаете возможность использовать полностью управляемый родителями Модаль, но вы удалили часть шаблона вокруг создания функции, которая устанавливает значение false и передает его модальному.

Ответ 2

Вы можете передать обратный вызов в качестве опоры для дочернего компонента:

// In the parent
<Modal display={this.state.showModal} onClose={this.closeModal} />

// In the modal
<div className={this.props.display ? "show" : "hide"}>
  <a className="close" onClick={this.props.onClose}>&times;</a>
  ...
</div>

Затем, когда вы нажимаете кнопку закрытия дочернего элемента, он вызывает функцию родительского