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),
    },
  },
});

더 알아보기 (Learn more)