index.tsx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  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. console.log(props)
  65. setModalProps(source => {
  66. return {
  67. ...source,
  68. ...props
  69. }
  70. })
  71. },
  72. // 打开Modal
  73. open: () => {
  74. onOpen()
  75. },
  76. // 关闭Modal
  77. close: () => {
  78. if (loading) setLoading(false)
  79. onClose()
  80. },
  81. // 设置表单数据
  82. setFieldsValue: (values: any) => {
  83. form.setFieldsValue?.(values)
  84. },
  85. setType: (type: string) => {
  86. typeRef.current = type
  87. }
  88. }),
  89. []
  90. )
  91. const handleOk = useCallback(() => {
  92. if (typeRef.current === 'form') {
  93. form.submit()
  94. } else {
  95. modalProps.onOk?.(null)
  96. }
  97. }, [form, modalProps])
  98. // 这里的Modal是ant.design中的Modal
  99. return (
  100. <Modal {...modalProps} onCancel={onClose} onOk={handleOk} okButtonProps={{ loading }}>
  101. {modalChildren
  102. ? React.cloneElement(modalChildren, {
  103. onFinish,
  104. form,
  105. onClose
  106. })
  107. : null}
  108. </Modal>
  109. )
  110. })
  111. )
  112. interface modalRefType {
  113. open: () => void
  114. close: () => void
  115. injectChildren: (child: React.ReactElement) => void
  116. injectModalProps: (props: ModalProps) => void
  117. setFieldsValue: (values: any) => void
  118. setType: (type: string) => void
  119. }
  120. interface OpenArgType extends ModalProps {
  121. children?: React.ReactElement
  122. type?: 'form' | 'default'
  123. initialValues?: {
  124. [key: string]: any
  125. }
  126. }
  127. /**
  128. * 适用于单弹窗模式
  129. */
  130. const useModal = () => {
  131. const modalRef = useRef<modalRefType>()
  132. const handle = useMemo(() => {
  133. return {
  134. open: ({ children, type, initialValues, ...rest }: OpenArgType) => {
  135. modalRef.current.setType(type)
  136. modalRef.current.injectChildren(children) // 注入子组件
  137. modalRef.current.injectModalProps(rest) // 注入Modal的参数
  138. modalRef.current.open()
  139. if (initialValues && type === 'form') {
  140. modalRef.current.setFieldsValue?.(initialValues)
  141. }
  142. },
  143. close: () => {
  144. modalRef.current.close()
  145. }
  146. }
  147. }, [])
  148. return [handle, <MyModal ref={modalRef} key={useId()} />] as const
  149. }
  150. export type ModalAction = {
  151. open: (args: OpenArgType) => void
  152. close: () => void
  153. }
  154. export default useModal