Kurs React Native · Moduł 5: Formularze

Walidacja z Yup i Zod

2 min czytania ·
W tej lekcji4

Schematy walidacji pozwalają definiować reguły w jednym miejscu.

Yup

npx expo install yup @hookform/resolvers
import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
import * as yup from 'yup';

// Schema walidacji
const schema = yup.object({
  name: yup
    .string()
    .required('Imię jest wymagane')
    .min(2, 'Min. 2 znaki')
    .max(50, 'Max. 50 znaków'),

  email: yup
    .string()
    .required('Email jest wymagany')
    .email('Nieprawidłowy format email'),

  password: yup
    .string()
    .required('Hasło jest wymagane')
    .min(8, 'Min. 8 znaków')
    .matches(/[a-z]/, 'Wymagana mała litera')
    .matches(/[A-Z]/, 'Wymagana wielka litera')
    .matches(/[0-9]/, 'Wymagana cyfra'),

  confirmPassword: yup
    .string()
    .required('Potwierdź hasło')
    .oneOf([yup.ref('password')], 'Hasła muszą być identyczne'),

  age: yup
    .number()
    .transform((value) => (isNaN(value) ? undefined : value))
    .required('Wiek jest wymagany')
    .min(18, 'Musisz mieć min. 18 lat')
    .max(120, 'Nieprawidłowy wiek'),

  terms: yup
    .boolean()
    .oneOf([true], 'Musisz zaakceptować regulamin'),
});

type FormData = yup.InferType<typeof schema>;

function YupForm() {
  const {
    control,
    handleSubmit,
    formState: { errors },
  } = useForm<FormData>({
    resolver: yupResolver(schema),
    defaultValues: {
      name: '',
      email: '',
      password: '',
      confirmPassword: '',
      age: undefined,
      terms: false,
    },
  });

  return (
    <View>
      {/* Pola formularza z Controller */}
    </View>
  );
}

Zod (alternatywa)

npx expo install zod @hookform/resolvers
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';

const schema = z.object({
  name: z
    .string()
    .min(1, 'Imię jest wymagane')
    .min(2, 'Min. 2 znaki'),

  email: z
    .string()
    .min(1, 'Email jest wymagany')
    .email('Nieprawidłowy email'),

  password: z
    .string()
    .min(8, 'Min. 8 znaków')
    .regex(/[a-z]/, 'Wymagana mała litera')
    .regex(/[A-Z]/, 'Wymagana wielka litera')
    .regex(/[0-9]/, 'Wymagana cyfra'),

  confirmPassword: z.string(),

  website: z
    .string()
    .url('Nieprawidłowy URL')
    .optional()
    .or(z.literal('')),
}).refine((data) => data.password === data.confirmPassword, {
  message: 'Hasła muszą być identyczne',
  path: ['confirmPassword'],
});

type FormData = z.infer<typeof schema>;

function ZodForm() {
  const { control, handleSubmit } = useForm<FormData>({
    resolver: zodResolver(schema),
  });

  // ...
}

Walidacja warunkowa

const schema = yup.object({
  hasCompany: yup.boolean(),

  companyName: yup.string().when('hasCompany', {
    is: true,
    then: (schema) => schema.required('Nazwa firmy wymagana'),
    otherwise: (schema) => schema.notRequired(),
  }),

  nip: yup.string().when('hasCompany', {
    is: true,
    then: (schema) =>
      schema
        .required('NIP wymagany')
        .matches(/^\d{10}$/, 'NIP musi mieć 10 cyfr'),
  }),
});

Asynchroniczna walidacja

const schema = yup.object({
  username: yup
    .string()
    .required()
    .test('unique', 'Nazwa zajęta', async (value) => {
      if (!value) return true;
      const response = await fetch(`/api/check-username?name=${value}`);
      const { available } = await response.json();
      return available;
    }),
});

Schematy walidacji to czytelny i wielokrotnie używalny sposób definiowania reguł!

Kod do tej lekcji: App.tsx
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { z } from 'zod';

// TODO: stwórz schemat walidacji za pomocą z.object({ ... }):
//   - email: z.string().email('Nieprawidłowy email')
//   - password: z.string().min(8, 'Min. 8 znaków')
//   - confirmPassword: z.string()
// Dodaj .refine(...) sprawdzający, czy password === confirmPassword
//   z message: 'Hasła muszą być identyczne' i path: ['confirmPassword']

// TODO: wyprowadź typ z schematu: type FormData = z.infer<typeof schema>

export default function App() {
  return (
    <View style={styles.container}>
      <Text style={styles.text}>
        Uzupełnij schemat walidacji Zod powyżej.
      </Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    justifyContent: 'center',
    backgroundColor: '#1a5276',
  },
  text: {
    fontSize: 16,
    color: '#aed6f1',
    textAlign: 'center',
  },
});

Hasła z dokumentacji w tej lekcji

Widzisz błąd w tej lekcji?

Sprawdź się

Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.

  1. 1. Jak połączyć Yup z react-hook-form?

  2. 2. Która biblioteka ma lepsze wsparcie TypeScript?

Zadania praktyczne w grze

  • Klikanie w kolejności

    Kliknij elementy schematu email w Yup:

  • Edytor kodu

    Uzupełnij schemat z walidacją email, hasła i potwierdzenia.

Przydatne artykuły