React Modal总是卸载并挂载子进程,因此ref回调有奇怪的行为。为什么不只是让孩子们重新投降呢?

时间:2017-01-20 14:52:44

标签: reactjs react-modal

我有一个反应模式,它呈现它的孩子:

// base_modal.js  
import React, { Component } from 'react';
import Modal from 'react-modal';

export default class BaseModal extends Component {
  componentDidMount() {
    console.log("BaseModal mounted");
  }

  render() {
    return (
      <Modal
        isOpen={this.props.showModal}
        className="base-modal"
        overlayClassName="base-modal-overlay"
        onRequestClose={this.props.onRequestClose}
        contentLabel="base-modal"
      >
        {this.props.children}
      </Modal>
    );
  }
}

我有另一个组件在一些孩子中渲染BaseModal:

// my_modal.js
import BaseModal from './base_modal'

export default class MyModal extends Component {
  constructor(props) {
    super(props);
    this.doSomeSetup = this.doSomeSetup.bind(this);
  }

  componentDidMount() {
    console.log("MyModal mounted");
    this.doSomeSetup();
  }

  doSomeSetup() {
    console.log(this.dateInput); // undefined
  }

  render() {
    return (
       <BaseModal
        showModal={this.props.showModal}
        onRequestClose={this.props.onClose}
       >
        <form>
          <div>
            <input
              ref={ input => { console.log("In the input ref"); this.dateInput = input; }}
              type='text'
              value={this.state.inputVal}
              onChange={this.handleChange}
            />
          </div>
        </form>
      </BaseModal>
    )
  }
}

我有一个呈现MyModal的组件:

// my_view.js
import MyModal from './my_modal'

export default class MyView extends Component {
  constructor(props) {
    super(props)
    this.state = {
      showModal: false
    }
    this.showModal = this.showModal.bind(this);
    this.hideModal = this.hideModal.bind(this);
  }

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

  hideModal() {
    this.setState({
      showModal: false
    });
  }

  render() {
    return (
      <div>
        <Button onClick={this.showModal} />
        <MyModal 
          showModal={false}
          onClose={this.hideModal}
        />
      </div>
    )
  }
}

问题是在MyModal中,组件安装时未定义this.dateInput。每当我渲染MyView时,它渲染MyModal,但MyModal渲染BaseModal,只有当它的“isOpen”设置为true时才会渲染它的子节点。

当我渲染MyView时,我看到控制台记录了“BaseModal已安装”,“MyModal已安装”,然后是doSomeSetup方法中的console.log的“undefined”(即,尚未执行ref回调)。当我单击MyView中的按钮打开模态时,我看到console.log“在输入引用中”。因此,我想要在MyModal中输入的设置没有发生,因为实际的表单输入的ref仅在React Modal将prop isOpen设置为true时执行。

另一种设置是进行以下更改:

// my_modal.js

componentDidMount() {
  console.log("MyModal mounted");
}

doSomeSetup(input) {
  console.log(input);
}


(...) ref={ input => { console.log("In the input ref"); this.doSomeSetup(input); }}

但是,现在,存在以下行为。当我渲染MyView时,我看到“BaseModal已安装”,“MyModal已安装”。当我单击Button打开模态时,我看到“在输入引用中”,实际的输入元素获得console.logged。

这是奇怪的事情(尽管我写这篇文章时我开始看到自己怀疑的答案):假设我在MyModal的渲染方法中添加了一个按钮,它只是改变了inputVal的状态,迫使重新投降:

  changeState() {
    this.setState({
      inputVal: this.state.inputVal + 1
    });
  }

  render() {
    return (
       <BaseModal
        showModal={this.props.showModal}
        onRequestClose={this.props.onClose}
       >
        <button onClick={this.changeState}
        <form>
          <div>
            <input
              ref={ input => { console.log("In the input ref"); this.doSomeSetup(input); }}
              type='text'
              value={this.state.inputVal}
              onChange={this.handleChange}
            />
          </div>
        </form>
      </BaseModal>
    )
  }

现在当我点击按钮是“在输入引用中”时会发生什么,然后执行doSomeSetup的console.log并生成“null”,然后我得到另一个“在输入引用中”,然后是控制台来自doSomeSetup的.log生成一个实际的输入元素。所以实际上看起来传递给BaseModal(我的按钮和窗体)的子项首先被卸载,然后再次挂载(我认为这是因为当节点将卸载时,以null作为参数调用ref回调)。这很奇怪。

所以现在,我想我的问题是:上述内容是否有意义,并且父组件每次卸载并安装其子项是否正常?这甚至是描述正在发生的事情的正确方法吗?

更准确地说,我想要的功能是在doSomeSetup中为输入添加一个事件处理程序。但似乎任何时候输入都要改变,因为它包含在BaseModal的子节点中,它是BaseModal的支柱,后者以某种方式决定卸载并挂载子节点。为什么不只是让孩子们重新投降呢?有更好的方法吗?

0 个答案:

没有答案