Hooks
Provides useReactiveForm and useDyForm and useDecorateForm to quickly update input values and manage form state.
TIP
Most of the types below are similar to the props in the vue3 version.
1. useReactiveForm
Used to wrap a DyFormItem[] with shallowReactive in a unified way.
Signature
export function useReactiveForm<T extends Record<string, any>, U = any>(
items: DyFormItem<T, U>[],
isReactive: boolean = true
): DyFormItem<T, U>[]Params
items:form item array (each item is aDyFormItem)isReactive:whether to wrap withshallowReactive(defaulttrue; passfalseto return the original array as-is)
Example
type FormRow = { username: string; password: string }
const formItems = useReactiveForm<FormRow>([
{
key: "username",
label: "Name",
value: ref<string | null>(null),
required: true,
render2: f => renderInput(f.value, {}, f),
},
{
key: "password",
label: "Password",
value: ref<string | null>(null),
required: true,
render2: f => renderInput(f.value, {showPasswordOn: "click"}, f),
},
{
key: "sex",
label: "Sex",
value: ref<number | null>(null),
render2: f => renderRadioGroup(f.value, [
{label: 'male', value: 0}, {label: 'female', value: 1},
], {}, f),
},
])2. useDyForm
Provides external control for a DyFormItem[]: disable, hide, set/get values, reset, etc.
Signature
export function useDyForm<Row extends Record<string, any>>(
items: DyFormItem<Row>[] | Ref<DyFormItem<Row>[]>
)Return Functions
setDisabled(disabled, keys?):batch disable/enable (if keys is omitted, applies to all)setHidden(hidden, keys?):batch hide/show (if keys is omitted, applies to all)setValue(key, value):set a single field valuesetValues(patch):batch set field valuesgetValue(key):get theDyFormItemobject for a given fieldgetValues(keys?):get form values (if keys is omitted, returns all; otherwise returns specified fields)onReset(value=null):reset all field values to the same value (defaultnull)getItem(key): Get theDyFormIteminstance for the specified field.setItem(key, {}): Set non-valueproperties for the specified field.setItems([[key, {}]]): Batch set non-valueproperties for specified fields.updateKeys([['username', 'name']]): Replace keys.
API usage example
Assume:
type FormRow = { username: string; password: string }
const useForm = useDyForm<FormRow>(formItems)1. Batch disable / enable
useForm.setDisabled(true) // disable all
useForm.setDisabled(true, ["username"]) // disable only username
useForm.setDisabled(false, ["password"]) // enable only password2. Batch hide / show
useForm.setHidden(true, ["username"]) // hide username
useForm.setHidden(false, ["username"]) // show username3. Set values (single / batch)
useForm.setValue("username", "zhangsan")
useForm.setValues({
username: "naive-ui",
password: "520",
})4. Get values
const all = useForm.getValues()
const part = useForm.getValues(["username"])
const part2 = useForm.getValue('username')5. Reset
useForm.onReset() // set all to null
useForm.onReset("") // set all to empty string6. Modify other values
useForm.setItem('username', {placeholder: 'please input username'}) // modify placeholder
useForm.setItems([
['username', {placeholder: 'please input username'}],
['password', {hidden: true}],
]) // Modify all properties of `DyFormItem` except `value`.7. Modify key
This method modifies keys directly, which can easily cause confusion. Use with caution.
useForm.updateKeys([['sex', 'gender']])3. useDecorateForm
Simplifies the render2 function by providing render types. It iterates and processes items, then wraps the DyFormItem[] with shallowReactive in a unified way.
Import from the UI adapter you choose, for example: import { useDecorateForm } from "dynamicformdjx/naiveUi";
Signature
// type
type RenderType =
| "renderInput"
| "renderSelect"
| "renderPopSelect"
| "renderTreeSelect"
| "renderRadioGroup"
| "renderRadioButtonGroup"
| "renderCheckboxGroup"
| "renderSwitch"
| "renderDatePicker"
| "renderTimePicker"
type DecorateDyFormItem<Row extends Record<string, any>, RuleT = any> =
Omit<DyFormItem<Row, RuleT>, "value"> & {
value: DyFormItem<Row, RuleT>["value"] | any | null
renderType?: RenderType
renderProps?: Record<string, any>
}
// function
export function useDecorateForm<Row extends Record<string, any>, RuleT = any>(
items: DecorateDyFormItem<Row, RuleT>[],
isReactive = true
): DyFormItem<T, U>[]Parameters
items:form item array (each item is aDecorateDyFormItem)isReactive:whether to wrap withshallowReactive(defaulttrue; passfalseto return the original array as-is)
DecorateDyFormItem
renderType:render type (from helpers provided in renderForm, e.g.("renderInput"| "renderSelect"| " renderPopSelect"| "renderTreeSelect"| " renderRadioGroup"| "renderRadioButtonGroup"| "renderCheckboxGroup"| "renderSwitch"| "renderDatePicker"| " renderTimePicker")renderProps:render props passed to the selected renderType, e.g. showPasswordOn: "click" forrenderInput
Example
type FormRow = { username: string; job: number }
const formItems = useDecorateForm<FormRow>([
{
key: "username",
label: "Name",
value: null,
required: true,
renderType: 'renderInput'
},
{
key: "job",
label: "Role",
value: null,
required: true,
options: ['Frontend', 'Backend'].map((label, value) => ({label, value})),
renderType: 'renderSelect'
},
])4. useStateCallback
A delayed state synchronization hook.
Signature
export function useStateCallback<T>(
initialValue: T
): [T, (value: SetStateAction<T>, cb?: (v: T) => void) => void]Parameters
initialValue: Initial value
Example
const [count, setCount] = useStateCallback<number>(0)
function handleCountChange() {
setCount(count + 1, p => {
console.log(p)
})
}5. usePagination
A pagination hook that provides basic pagination configuration.
Signature
export type PageModal = {
pageSize: number
pageNo: number
total: number
}
export type ZealPagination = {
showSizePicker: boolean
pageCount?: number
pageSizes: number[]
pageSlot?: number
onChange: (pageNo: number, pageSize: number) => void;
onPageSizeChange: (pageSize?: number) => void;
layout?: string
} & PageModal
export function usePagination(
cb?: (pageNo: number, pageSize?: number) => void, options?: Partial<ZealPagination>
): {
pagination: ZealPagination
pageModalRef: React.MutableRefObject<PageModal>
setPageNo: (pageNo: number, skip?: boolean) => void
setPageSize: (pageSize: number, skip?: boolean) => void
setTotal: (total: number) => void
}Parameters
cb: Request callback, triggered when the internal page number or page size changesoptions: Initial pagination configuration, merged with the default values if provided
Example
const {pagination} = usePagination(fetchData)
function fetchData(pn: number, ps: number) {
const {pageNo, pageSize} = paginaton
// ...
}6. useWindowSize
Listens to window size changes and provides the updated width and height.
Signature
type SizeObjType = { isMobile: boolean, width: number, height: number };
export function useWindowSize(
mobileWidth: number, delay: number
): SizeObjTypeParameters
mobileWidth: Maximum width for mobile mode. Whenwidthis smaller than this value,isMobilewill betrue. Default is756delay: Delay in milliseconds. When the window width or height changes, the updated value is returned after this delay. Default is500
Example
const {isMobile, width, height} = useWindowSize()7. useObserverSize
Calculates the remaining inner content height.
Signature
export type CtxHeightState = {
wrapInnerH: number;
restH: number;
headerH: number;
footerH: number;
contentPadY: number;
}
export function useObserverSize(delay: number): {
wrapRef: React.MutableRefObject<HTMLDivElement | null>;
cardRef: React.MutableRefObject<HTMLDivElement | null>;
restRef: React.MutableRefObject<HTMLDivElement | null>;
tableHeight: number;
calc: () => void;
ctxHeight: CtxHeightState
}Parameters
delay: Delay time
Example
Example using Antd
Card
import {useObserverSize} from "dynamicformdjx-react";
import {Card} from "antd";
import {RefObject} from "react";
function CardTest() {
const zealHeight = '100vh'
const outPadding = 20
const {wrapRef, cardRef, restRef, tableHeight, ctxHeight} = useObserverSize();
return <div className='container' ref={wrapRef}>
<div
className="zealCard"
style={{
height: `calc(${zealHeight} - ${outPadding * 2}px)`,
}}
ref={wrapRef}
>
<Card
ref={cardRef as RefObject<HTMLDivElement>}
title={<div className='title'>
</div>}
actions={[
<div className='footer'></div>
]}
style={{height: "100%"}}
styles={{
header: {
padding: '10px'
},
body: {
padding: '1px',
height: tableHeight + 'px',
},
}}
>
<div className="content">
</div>
</Card>
<div ref={restRef}></div>
</div>
</div>
}
export default CardTest;