Skip to content

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

ts
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 a DyFormItem)
  • isReactive:whether to wrap with shallowReactive (default true; pass false to return the original array as-is)

Example

ts
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

ts
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 value
  • setValues(patch):batch set field values
  • getValue(key):get the DyFormItem object for a given field
  • getValues(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 (default null)
  • getItem(key): Get the DyFormItem instance for the specified field.
  • setItem(key, {}): Set non-value properties for the specified field.
  • setItems([[key, {}]]): Batch set non-value properties for specified fields.
  • updateKeys([['username', 'name']]): Replace keys.

API usage example

Assume:

ts
type FormRow = { username: string; password: string }
const useForm = useDyForm<FormRow>(formItems)

1. Batch disable / enable

ts
useForm.setDisabled(true)                 // disable all
useForm.setDisabled(true, ["username"])   // disable only username
useForm.setDisabled(false, ["password"])  // enable only password

2. Batch hide / show

ts
useForm.setHidden(true, ["username"])     // hide username
useForm.setHidden(false, ["username"])    // show username

3. Set values (single / batch)

ts
useForm.setValue("username", "zhangsan")

useForm.setValues({
    username: "naive-ui",
    password: "520",
})

4. Get values

ts
const all = useForm.getValues()
const part = useForm.getValues(["username"])
const part2 = useForm.getValue('username')

5. Reset

ts
useForm.onReset()     // set all to null
useForm.onReset("")   // set all to empty string

6. Modify other values

ts
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.

ts
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

ts
// 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 a DecorateDyFormItem)
  • isReactive:whether to wrap with shallowReactive (default true; pass false to 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" for renderInput

Example

ts
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

ts
export function useStateCallback<T>(
        initialValue: T
): [T, (value: SetStateAction<T>, cb?: (v: T) => void) => void]

Parameters

  • initialValue: Initial value

Example

ts
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

ts
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 changes
  • options: Initial pagination configuration, merged with the default values if provided

Example

ts
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

ts
type SizeObjType = { isMobile: boolean, width: number, height: number };

export function useWindowSize(
        mobileWidth: number, delay: number
): SizeObjType

Parameters

  • mobileWidth: Maximum width for mobile mode. When width is smaller than this value, isMobile will be true. Default is 756
  • delay: Delay in milliseconds. When the window width or height changes, the updated value is returned after this delay. Default is 500

Example

ts
const {isMobile, width, height} = useWindowSize()

7. useObserverSize

Calculates the remaining inner content height.

Signature

ts
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

tsx
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;