首页 > 解决方案 > 替代在子组件上调用方法?

问题描述

我有以下组件,其中包含一个下拉菜单,其项目通过调用子组件上的方法打开模式:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.modal = React.createRef();
  }

  render() {
    ...

    let dropdownItems;

    if (isCreate) {
      dropdownItems = <>
        { /* Calling open() on the child component */ }
        <Dropdown.Item onClick={() => {this.modal.current.open()}}>Create</Dropdown.Item>
      </>;
    } else {
      dropdownItems = <>
        { /* Same thing, from another item */ }
        <Dropdown.Item onClick={() => {this.modal.current.open()}}>Edit</Dropdown.Item>
        <Dropdown.Item>Delete</Dropdown.Item>
      </>;
    }

    return (
      <Dropdown>
        <Dropdown.Toggle as={CustomDropdownToggle} id={dropdownId} />
          <Dropdown.Menu>
            <Dropdown.Header>...</Dropdown.Header>

            {dropdownItems}

            { /* Storing a reference to the child component */ }
            <EditMatchModal ref={this.modal} productMatch={productMatch} />
          </Dropdown.Menu>
      </Dropdown>
    );
  }
}
class EditMatchModal extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isOpen: false };
  }

  open() {
    this.setState({ isOpen: true });
    this.loadData();
  }

  loadData() {
    // Perform AJAX request...
  }

  render() {
    return (
      <Modal>
        ...
      </Modal>
    );
  }
}

这很好用,但是我在这里文档中读到 refs 是一个逃生舱口,通常应该避免这种情况

在这种情况下,避免使用 refs 的更好选择是什么?

一种解决方案是将isOpen属性移动到 parent MyComponent,但是:

另一种解决方案是将打开模式的按钮移动到EditMatchModal自身,但是:

我错过了什么?

标签: reactjs

解决方案


我不同意该isOpen属性属于模态。最好将状态提升到最近的公共父组件。例如,最近的公共父组件<Dropdown.Item /><Modal />是您的父组件,<MyComponent />。您可以使用如下所示的onClick方法<Dropdown.Item />

<Dropdown.Item onClick={this.toggleModal}>Edit</Dropdown.Item>
// In MyComponent
state = {
  modalIsOpen: false
}

toggleModal = () => {
  this.setState({
     modalIsOpen: true
  })
}

然后根据状态有条件地渲染您的模态:

{this.state.modalIsOpen && <EditMatchModal productMatch={productMatch} /> }

您可能需要模态本身中的一个方法来关闭模态(或您想要关闭模态的任何其他位置),这需要一个设置state.modalIsOpen为 false 的回调。

这干净多了。您不需要 ref 或模态本身中的方法。当模态应该打开或不打开时,从父级可以清楚地看到。通过影响状态很容易影响其状态。如果任何其他孩子需要打开模态框,您必须为他们提供回调以回调this.toggleModal. 或者,如果树下的组件需要影响它,您应该考虑更强大的状态管理策略。

至于进行 ajax 调用,您仍然可以在componentDidMountmodal 中保留任何 ajax 调用。

编辑:对于 React-BootStrap

在评论中发现这是使用 React-Bootstrap (RB)。在这种情况下,您不需要有条件地渲染<Modal />- RB ​​为您处理。如上所述,您的方法仍应是父方法,但现在您可以像这样呈现模态:

// In MyComponent
<EditMatchModal show={this.state.modalIsOpen} productMatch={productMatch} />

// EditMatchModal
class EditMatchModal extends React.Component {

  loadData() {
    // Perform AJAX request...
  }

  render() {
    return (
      <Modal show={this.props.show}>
        ...
      </Modal>
    );
  }
}

推荐阅读