index.tsx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. import React, {
  2. useRef,
  3. useMemo,
  4. memo,
  5. forwardRef,
  6. useCallback,
  7. useState,
  8. useImperativeHandle,
  9. useId
  10. } from 'react'
  11. import { Modal, Form } from 'antd'
  12. import type { ModalProps } from 'antd'
  13. const MyModal = memo(
  14. forwardRef((prop: any, ref) => {
  15. const [form] = Form.useForm()
  16. const [modalChildren, setModalChildren] = useState<React.ReactElement>(null)
  17. const [loading, setLoading] = useState(false)
  18. const [modalProps, setModalProps] = useState<ModalProps>({
  19. visible: false
  20. })
  21. const typeRef = useRef<string>()
  22. const onFinish = useCallback(
  23. (values: any) => {
  24. const response = modalProps.onOk?.(values)
  25. if (response instanceof Promise) {
  26. setLoading(true)
  27. response.finally(() => {
  28. setLoading(false)
  29. })
  30. }
  31. },
  32. [form, modalProps]
  33. )
  34. // ant.design 4.0 Form的onFinish触发回调
  35. // const onFinish = useCallback(
  36. // (values: any) => {
  37. // modalProps.onOk?.(values)
  38. // },
  39. // [form, modalProps]
  40. // )
  41. // 关闭当前Modal
  42. const onClose = useCallback(() => {
  43. setModalProps(source => ({
  44. ...source,
  45. visible: false
  46. }))
  47. }, [form])
  48. // 关闭当前Modal
  49. const onOpen = useCallback(() => {
  50. setModalProps(source => ({
  51. ...source,
  52. visible: true
  53. }))
  54. }, [form])
  55. useImperativeHandle(
  56. ref,
  57. () => ({
  58. // 注入Modal的子组件
  59. injectChildren: element => {
  60. setModalChildren(element)
  61. },
  62. // 注入Modal参数
  63. injectModalProps: props => {
  64. setModalProps(source => {
  65. return {
  66. ...source,
  67. ...props
  68. }
  69. })
  70. },
  71. // 打开Modal
  72. open: () => {
  73. onOpen()
  74. },
  75. // 关闭Modal
  76. close: () => {
  77. if (loading) setLoading(false)
  78. onClose()
  79. },
  80. // 设置表单数据
  81. setFieldsValue: (values: any) => {
  82. form.setFieldsValue?.(values)
  83. },
  84. setType: (type: string) => {
  85. typeRef.current = type
  86. }
  87. }),
  88. []
  89. )
  90. const handleOk = useCallback(() => {
  91. if (typeRef.current === 'form') {
  92. form.submit()
  93. } else {
  94. modalProps.onOk?.(null)
  95. }
  96. }, [form, modalProps])
  97. // 这里的Modal是ant.design中的Modal
  98. return (
  99. <Modal {...modalProps} onCancel={onClose} onOk={handleOk} okButtonProps={{ loading }} destroyOnClose>
  100. {modalChildren
  101. ? React.cloneElement(modalChildren, {
  102. onFinish,
  103. form,
  104. onClose
  105. })
  106. : null}
  107. </Modal>
  108. )
  109. })
  110. )
  111. interface modalRefType {
  112. open: () => void
  113. close: () => void
  114. injectChildren: (child: React.ReactElement) => void
  115. injectModalProps: (props: ModalProps) => void
  116. setFieldsValue: (values: any) => void
  117. setType: (type: string) => void
  118. }
  119. interface OpenArgType extends ModalProps {
  120. children?: React.ReactElement
  121. type?: 'form' | 'default'
  122. initialValues?: {
  123. [key: string]: any
  124. }
  125. }
  126. /**
  127. * 适用于单弹窗模式
  128. */
  129. const useModal = () => {
  130. const modalRef = useRef<modalRefType>()
  131. const handle = useMemo(() => {
  132. return {
  133. open: ({ children, type, initialValues, ...rest }: OpenArgType) => {
  134. modalRef.current.setType(type)
  135. modalRef.current.injectChildren(children) // 注入子组件
  136. modalRef.current.injectModalProps(rest) // 注入Modal的参数
  137. modalRef.current.open()
  138. if (initialValues && type === 'form') {
  139. modalRef.current.setFieldsValue?.(initialValues)
  140. }
  141. },
  142. close: () => {
  143. modalRef.current.close()
  144. }
  145. }
  146. }, [])
  147. return [handle, <MyModal ref={modalRef} key={useId()} />] as const
  148. }
  149. export type ModalAction = {
  150. open: (args: OpenArgType) => void
  151. close: () => void
  152. }
  153. export default useModal