reactjs - 替代在子组件上调用方法?
问题描述
我有以下组件,其中包含一个下拉菜单,其项目通过调用子组件上的方法打开模式:
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
,但是:
- 真的感觉是属于modal组件的
- 更改后,它必须立即触发 AJAX 请求,因此将方法放在 AJAX 代码所在的模式上是有意义的
另一种解决方案是将打开模式的按钮移动到EditMatchModal
自身,但是:
- 有 2 个按钮,所以这会复制模态组件(这很重要吗?)
- 按钮不仅仅是按钮,而是
<Dropdown>
项目,所以父组件的呈现会泄漏到子组件中,这对我来说是一个很大的气味
我错过了什么?
解决方案
我不同意该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 调用,您仍然可以在componentDidMount
modal 中保留任何 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>
);
}
}