如何正确地从React自定义钩子导出组件和控制它的函数



我想做的是创建一种可重复使用且方便的方式来显示警报或确认模式。

使用库模态通常需要导入模态组件并创建状态变量,然后将其作为道具传递给导入的组件以控制其可见性。我想做的是创建一个自定义挂钩,它导出一个带有所有自定义的模态组件(可能是库中模态组件的包装器(和一个切换可见性的函数。下面是这样的。这是挂钩代码:

import React, {useState} from 'react'
import 'antd/dist/antd.css'
import {Modal as AntdModal} from 'antd'
const useModal = () => {
const [on, setOn] = useState(false)
const toggleModal = () => setOn(!on)
const Modal = ({onOK, ...rest}) => (
<AntdModal
{...rest}
visible={on}
onOk={() => {
onOK && onOK()
toggleModal()
}}
onCancel={toggleModal}
/>
)
return {
on,
toggleModal,
Modal,
}
}
export default useModal

这就是我使用它的方式:

import React, {useState} from 'react'
import ReactDOM from 'react-dom'
import useModal from './useModal'
import {Button} from 'antd'
const App = () => {
const {toggleModal, Modal} = useModal()
return (
<div>
<Button type="primary" onClick={toggleModal}>
Open Modal
</Button>
<Modal title="Simple" onOK={() => alert('Something is not OK :(')}>
<p>Modal content...</p>
</Modal>
</div>
)
}
const rootElement = document.getElementById('root')
ReactDOM.render(<App />, rootElement)

这里有一个沙盒,可以看到它的实际操作并进行测试。有两个按钮,一个显示通常从库(此处为antd(导入的Modal,另一个显示自定义挂钩useModal

钩子的一种形式是有效的,只是看起来有问题。出现的过渡是有效的。但当你关闭模态时,它突然消失了,没有过渡。组件似乎在转换出去之前就被立即销毁了。我做错了什么?

如果我理解正确,您需要渲染一个组件,并且还需要一个可以控制它的函数(切换它的可见性(。

虽然这不可能像您试图用react hooks实现的那样,因为在状态更改时,您实际上也在更新Modal,这会导致从DOM卸载Dialogue

您可以使用以下解决方案来获得相同的结果。该解决方案使用一个带有forwardRefuseImperativeHandle的组件,并将实现一个解耦功能,您可以使用该功能通过点击按钮切换对话:

注意:您需要从v-16.7.0-alpha(如您的沙箱代码中所示(升级到reactreact-dom,直到最新版本(16.14.0([我没有尝试过其他中间版本]

模态组件:

import React, {useState, forwardRef, useImperativeHandle} from 'react'
import 'antd/dist/antd.css'
import {Modal as AntdModal} from 'antd'
const Modal = forwardRef(({onOK, ...rest}, ref) => {
useImperativeHandle(ref, () => ({
toggleModal: toggleModal
}));
const [on, setOn] = useState(false)
const toggleModal = () => setOn(!on)
return (
<AntdModal
{...rest}
visible={on}
onOk={() => {
onOK && onOK()
toggleModal()
}}
onCancel={toggleModal}
/>
)
});
export default Modal;

这就是如何使用它:

import React, {useState, useRef} from 'react'
import ReactDOM from 'react-dom'
import Modal from './ModalWrapper'
import {Button, Modal as AntdModal} from 'antd'
const App = () => {
const [on, setOn] = useState(false)
const toggle = () => setOn(!on)
const modalRef = useRef()
return (
<div>
<Button type="warning" onClick={() => setOn(true)}>
Normal Import
</Button>
<br />
<br />
<Button type="primary" onClick={() => modalRef.current.toggleModal()}>
From Modal Component
</Button>
<AntdModal visible={on} onOk={toggle} onCancel={toggle}>
<p>I was imported directly...</p>
<p>I was imported directly...</p>
<p>I was imported directly...</p>
</AntdModal>
<Modal
title="Simple"
ref={modalRef}
onOK={() => alert('Things are now OK :)')}
>
<p>I was imported from Modal Component...</p>
<p>I was imported from Modal Component...</p>
<p>I was imported from Modal Component...</p>
</Modal>
</div>
)
}
const rootElement = document.getElementById('root')
ReactDOM.render(<App />, rootElement)

我希望它能帮助你的用例。

谢谢。

最新更新