Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | 2x 2x 6x 2x 2x 1x 2x 4x 4x 4x 4x 2x 1x 1x 1x 1x 2x 1x 1x 1x 1x 2x 15x 15x 15x 12x 10x 10x 2x 15x 15x | import React, { useCallback, useEffect, useRef, useState } from 'react'
import { IState, ValueOf } from 'formstate-x'
import {
Form as BaseForm, FormProps as BaseFormProps,
ModalForm as BaseModalForm, ModalFormProps as BaseModalFormProps,
DrawerForm as BaseDrawerForm, DrawerFormProps as BaseDrawerFormProps
} from 'react-icecream'
export type SubmitHandler<V> = (value: V) => (void | Promise<void>)
export type WithState<
BaseProps extends { onSubmit?: SubmitHandler<void> },
S extends IState<V>,
V = ValueOf<S>
> = (
Omit<BaseProps, 'onSubmit'>
& {
/** 表单状态,`FormState` 实例 */
state: S
/** 提交行为的回调函数,表单校验通过才会触发回调 */
onSubmit?: SubmitHandler<V>
}
)
function useValidatedSubmit<V>(onSubmit: SubmitHandler<V> | undefined, state: IState<V>) {
return useCallback(async () => {
const validated = await state.validate()
if (validated.hasError) return
return onSubmit?.(validated.value)
}, [state, onSubmit])
}
export type Props<S extends IState<V>, V = ValueOf<S>> = WithState<BaseFormProps, S, V>
export default function Form<S extends IState<V>, V = ValueOf<S>>({
state,
onSubmit,
...formProps
}: Props<S, V>) {
const handleSubmit = useValidatedSubmit(onSubmit, state)
return <BaseForm {...formProps} onSubmit={handleSubmit} />
}
export type ModalFormProps<S extends IState<V>, V = ValueOf<S>> = WithState<BaseModalFormProps, S, V>
export function ModalForm<S extends IState<V>, V = ValueOf<S>>({
state,
onSubmit,
...modalFormProps
}: ModalFormProps<S, V>) {
const handleSubmit = useValidatedSubmit(onSubmit, state)
return <BaseModalForm {...modalFormProps} onSubmit={handleSubmit} />
}
export type DrawerFormProps<S extends IState<V>, V = ValueOf<S>> = WithState<BaseDrawerFormProps, S, V>
export function DrawerForm<S extends IState<V>, V = ValueOf<S>>({
state,
onSubmit,
...drawerFormProps
}: DrawerFormProps<S, V>) {
const handleSubmit = useValidatedSubmit(onSubmit, state)
return <BaseDrawerForm {...drawerFormProps} onSubmit={handleSubmit} />
}
/**
* 在 React 组件中构造 `FormState` / `FieldState` 实例的 hooks
*
* 使用姿势:
* function createState(foo: Foo, bar?: Bar) {
* return new FormState({
* foo: new FieldState(foo)
* bar: new FieldState(bar)
* })
* }
*
* function Comp({ foo, bar }) {
* const state = useFormstateX(createState, [foo, bar])
* }
* */
export function useFormstateX<D extends readonly any[], R extends IState, Fn extends(...args: D) => R>(
createState: Fn,
parameters: [...D]) {
const [state, setState] = useState(() => createState(...parameters))
const isFirstRef = useRef(true)
useEffect(() => {
// 跳过第一次 render 后的 effect,避免 state 的重复构造与替换;
// 此时 createState 未发生变更,render 时所构造的 state 依然可用
if (isFirstRef.current) {
isFirstRef.current = false
return
}
setState(createState(...parameters))
}, parameters) // eslint-disable-line react-hooks/exhaustive-deps
useEffect(() => state.dispose, [state])
return state as ReturnType<Fn>
}
|