Nested fields
Nested fields
use-form 훅으로 중첩된 배열과 객체 상태를 관리하는 방법을 다루는 문서예요. 속성 경로(property path)를 사용해 중첩된 필드에 접근하고 조작해요.
출처: 문서
본문
속성 경로 (Property paths)
대부분의 form 핸들러는 첫 번째 인자로 속성 경로를 받아요. 속성 경로는 대상 속성이 포함된 객체/배열의 키/인덱스를 포함해요.
import { useForm } from '@mantine/form';
const form = useForm({
mode: 'uncontrolled',
initialValues: {
user: {
firstName: 'John',
lastName: 'Doe',
},
fruits: [
{ name: 'Banana', available: true },
{ name: 'Orange', available: false },
],
deeply: {
nested: {
object: [{ item: 1 }, { item: 2 }],
},
},
},
});
// user 객체의 firstName 필드로 제어되는 입력을 위한 props
form.getInputProps('user.firstName');
// fruits 배열 두 번째 위치의 객체에 포함된 `name` 필드의 값 설정:
form.setFieldValue('fruits.1.name', 'Carrot');
// 깊게 중첩된 필드 검증
await form.validateField('deeply.nested.object.0.item');
중첩된 객체 (Nested objects)
import { useForm } from '@mantine/form';
import { Box, Checkbox, TextInput } from '@mantine/core';
function Demo() {
const form = useForm({
mode: 'uncontrolled',
initialValues: {
terms: false,
user: {
firstName: '',
lastName: '',
},
},
});
return (
<Box maw={400} mx="auto">
<TextInput label="First name" placeholder="First name" {...form.getInputProps('user.firstName')} />
<TextInput label="Last name" placeholder="Last name" mt="md" {...form.getInputProps('user.lastName')} />
<Checkbox label="I accept terms and conditions" mt="sm" {...form.getInputProps('terms', { type: 'checkbox' })} />
</Box>
);
}
중첩된 객체 값 설정 (Set nested object value)
import { useForm } from '@mantine/form';
const form = useForm({
mode: 'uncontrolled',
initialValues: {
user: {
name: '',
occupation: '',
},
},
});
// 각 필드의 값을 개별적으로 설정할 수 있어요
form.setFieldValue('user.name', 'John');
form.setFieldValue('user.occupation', 'Engineer');
// 또는 전체 객체를 설정할 수 있어요
form.setFieldValue('user', { name: 'Jane', occupation: 'Architect' });
중첩된 객체 값 검증 (Nested object value validation)
import { useForm } from '@mantine/form';
const form = useForm({
mode: 'uncontrolled',
initialValues: {
user: {
name: '',
occupation: '',
},
},
validate: {
user: {
name: (value) => (value.length < 2 ? 'Name is too short' : null),
occupation: (value) => (value.length < 2 ? 'Occupation is too short' : null),
},
},
});
// validation처럼 오류는 경로 기반으로 반환돼요:
// { 'user.name': 'Name is too short', 'user.occupation': 'Occupation is too short' }
중첩된 배열 (Nested arrays)
import { useForm } from '@mantine/form';
import { TextInput, Switch, Group, ActionIcon, Box, Text, Button } from '@mantine/core';
import { randomId } from '@mantine/hooks';
import { TrashIcon } from '@phosphor-icons/react';
function Demo() {
const form = useForm({
mode: 'uncontrolled',
initialValues: {
employees: [{ name: '', active: false, key: randomId() }],
},
});
const fields = form.getValues().employees.map((item, index) => (
<Group key={item.key} mt="xs">
<TextInput
placeholder="Name"
{...form.getInputProps(`employees.${index}.name`)}
/>
<Switch
label="Active"
{...form.getInputProps(`employees.${index}.active`, { type: 'checkbox' })}
/>
<ActionIcon color="red" onClick={() => form.removeListItem('employees', index)}>
<TrashIcon size={16} />
</ActionIcon>
</Group>
));
return (
<Box maw={500} mx="auto">
{fields.length > 0 ? (
<Group mb="xs">
<Text fw={500} size="sm" style={{ flex: 1 }}>Name</Text>
<Text fw={500} size="sm" pr={90}>Status</Text>
</Group>
) : (
<Text c="dimmed" ta="center">No one here...</Text>
)}
{fields}
<Group justify="center" mt="md">
<Button onClick={() => form.insertListItem('employees', { name: '', active: false, key: randomId() })}>
Add employee
</Button>
</Group>
</Box>
);
}
목록 핸들러 (List handlers)
useForm 훅은 목록 상태를 관리하기 위한 다음 핸들러를 제공해요.
removeListItem– 주어진 인덱스의 목록 항목을 제거해요insertListItem– 주어진 인덱스에 목록 항목을 삽입해요(인덱스를 지정하지 않으면 목록 끝에 항목을 추가해요)reorderListItem– 지정된 필드에서 주어진 위치의 목록 항목을 재정렬해요replaceListItem– 주어진 인덱스의 목록 항목을 새 값으로 교체해요
목록 값 검증 (List value validation)
import { useForm } from '@mantine/form';
const form = useForm({
mode: 'uncontrolled',
initialValues: {
users: [
{ name: 'John', age: 12 },
{ name: '', age: 22 },
],
},
validate: {
users: {
name: (value) => (value.length < 2 ? 'Name is too short' : null),
age: (value) => (value < 18 ? 'Must be at least 18' : null),
},
},
});