메인 콘텐츠로 건너뛰기

Form 폼

LhForm + LhFormItem으로 구성된 복합 컴포넌트로, 데이터 유효성 검사, 오류 표시, 레이블 정렬 등의 기능을 제공합니다.

기본 사용법​

유효성 검사 폼
import { useRef, useState } from 'react'
import { LhButton, LhForm, LhFormItem, LhInput, LhSelect } from '@lh-ui/react'
import type { LhFormInstance, LhFormRule } from '@lh-ui/react'

interface FormData {
name: string
style: string
}

const rules: Record<string, LhFormRule[]> = {
name: [{ required: true, message: '작품 이름을 입력하세요', trigger: 'blur' }],
style: [{ required: true, message: '화풍을 선택하세요', trigger: 'change' }],
}

export default function Demo() {
const [formData, setFormData] = useState<FormData>({ name: '', style: '' })
const formRef = useRef<LhFormInstance>(null)

const handleSubmit = async () => {
const valid = await formRef.current?.validate()
if (valid) alert(`제출 성공: ${formData.name} / ${formData.style}`)
}

const handleReset = () => {
formRef.current?.resetFields()
setFormData({ name: '', style: '' })
}

return (
<LhForm ref={formRef} model={formData} rules={rules} labelWidth="80px">
<LhFormItem label="작품 이름" prop="name">
<LhInput
value={formData.name}
onChange={(val) => setFormData((prev) => ({ ...prev, name: val }))}
/>
</LhFormItem>
<LhFormItem label="화풍" prop="style">
<LhSelect
value={formData.style}
onChange={(val) => setFormData((prev) => ({ ...prev, style: val as string }))}
options={[{ label: '수묵', value: 'ink' }]}
/>
</LhFormItem>
<LhFormItem>
<LhButton type="primary" onClick={handleSubmit}>제출</LhButton>
<LhButton onClick={handleReset}>재설정</LhButton>
</LhFormItem>
</LhForm>
)
}

Form Props​

프로퍼티설명타입기본값
model폼 데이터 객체 (필수)Record<string, unknown>—
rules유효성 검사 규칙, 키는 필드명Record<string, LhFormRule[]>—
labelWidth레이블 너비string | number—
labelPosition레이블 위치'left' | 'right' | 'top''right'
inline인라인 레이아웃booleanfalse
disabled모든 자식 항목 비활성화booleanfalse
size자식 항목 크기'large' | 'middle' | 'small'ConfigProvider 따름
onSubmit기본 제출 이벤트 (preventDefault 적용됨)(event: FormEvent) => void—

FormItem Props​

프로퍼티설명타입기본값
label레이블 문구string—
prop필드명 (점 경로 지원, model의 키에 대응)string—
rules항목 수준의 규칙 (동명일 때 form 수준을 덮어씀)LhFormRule[]—
required필수 별표 (표시만 하고, 유효성 검사 의미는 rules가 제공)booleanfalse
labelWidthform 수준 레이블 너비 덮어씀string | number—
errorMessage사용자 지정 오류 메시지string—
showMessage오류 표시booleantrue

LhFormRule​

프로퍼티설명타입
required필수 여부boolean
message유효성 검사 실패 메시지string
trigger발생 방식'blur' | 'change'
validator사용자 지정 유효성 검사 함수 (Promise 반환 가능, 비동기 유효성 검사를 올바르게 기다림)(value, model) => string | undefined | Promise<string | undefined>
min / max최솟값 / 최댓값 (숫자 또는 길이)number
pattern정규식 유효성 검사RegExp

Form ref 메서드​

LhFormInstance (forwardRef + useImperativeHandle로 노출):

메서드설명반환값
validate모든 필드 유효성 검사Promise<boolean>
validateField단일 필드 유효성 검사Promise<boolean>
resetFields모든 필드를 초기값으로 재설정void
resetField단일 필드 재설정void
const formRef = useRef<LhFormInstance>(null)
const ok = await formRef.current?.validate()
비동기 유효성 검사

이 라이브러리는 plus의 비동기 유효성 검사 결함을 수정했습니다. plus의 validateField는 Promise.resolve(!message)를 사용해 비동기 validator의 Promise를 기다리지 않아, 비동기 유효성 검사가 항상 true를 반환합니다. React 버전은 thenable이 완료된 후에 명시적으로 판정합니다. 자세한 내용은 마이그레이션 가이드를 참조하세요.

필드 등록

LhFormItem은 useEffect에서 form에 유효성 검사기를 등록하고, 언마운트 시 자동으로 등록을 취소합니다. 필드를 rules에 미리 선언할 필요가 없습니다. rules에는 없지만 model에는 있는 필드의 초기값은 등록 시점에 채워집니다.

trigger의 의미 (React 강화)

share의 validateFormField는 trigger를 해석하지 않으며, 발생 시점은 이 계층의 연결이 담당합니다. trigger: 'blur' (기본값)는 FormItem이 포커스를 잃을 때 유효성 검사를, trigger: 'change'는 콘텐츠 영역의 change로 유효성 검사를 수행합니다. trigger가 표시되어 있지 않은 규칙은 포커스 상실과 validate()일 때만 실행되며, 입력 도중에는 반복해서 오류가 표시되지 않습니다.

change 유효성 검사는 model 스냅샷이 아닌 이벤트 대상의 새 값을 가져옵니다. React의 상태 업데이트와 이벤트 전달은 같은 틱에 일어나지 않아, model을 다시 읽으면 한 틱 뒤처집니다. 기본 컨트롤 (input / textarea / 기본 select)의 change 이벤트는 콘텐츠 영역으로 버블링되어 캡처됩니다. 커스텀 컨트롤에는 기본 change 이벤트가 없어 (LhSelect의 옵션 클릭은 click만 발생), FormItem 컨텍스트의 validateChange(value)로 새 값을 직접 전달합니다.

재설정 시 오류 제거 (React 강화)

resetFields()는 model을 초기값 스냅샷으로 되돌리는 외에도 내부 resetVersion을 증가시키며, 각 FormItem은 버전 변화를 감지해 자신의 오류 상태를 비웁니다. 외부 제어 상태는 여전히 직접 동기화해야 합니다 (데모의 setFormData(initial)처럼). React는 Vue의 reactive 연쇄처럼 model을 대신 작성할 수 없습니다.

스타일​

import '@lh-ui/react/style/form'