1

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

// 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 的“未定义”(即尚未执行 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 已安装”。当我单击按钮打开模式时,我看到“在输入引用中”并且实际的输入元素被 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”,然后我得到另一个“在输入引用中”,然后是来自的 console.log doSomeSetup 产生一个实际的输入元素。所以实际上似乎传递给 BaseModal 的子项(我的按钮和表单)首先被卸载,然后再次被安装(我认为这是因为当节点卸载时,引用回调被调用为 null 作为参数)。这很奇怪。

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

更准确地说,我想要的功能是将事件处理程序添加到 doSomeSetup 中的输入。但似乎任何时候输入都要改变,因为它包含在 BaseModal 的一个子节点中,它是 BaseModal 的一个道具,后者以某种方式决定卸载和安装子节点。为什么不只是重新渲染孩子?有一个更好的方法吗?

4

0 回答 0