← все проекты
Личный проект2022

React SPA

Учебный проект: роутинг и валидация форм

Скриншот: React SPA

Что это за проект

Три страницы под общим layout с Outlet, состояние на хуках и форма с валидацией через react-hook-form: обязательность, минимальная длина, блокировка отправки до валидности. Показан как учебный, без претензии на кейс.

Моя роль

Личный учебный проект.

Стек

  • React 17
  • React Router 6
  • react-hook-form
  • Tailwind

Что внутри стоит посмотреть

  • Вложенный роутинг через Outlet
  • Валидация формы с блокировкой отправки
  • Клиентский роутинг работает по прямой ссылке

Технические решения

Выдержки из настоящих файлов проекта — путь к каждому указан над кодом.

Вложенные маршруты через общий layout

Шапка не дублируется по страницам: маршруты вложены в один Layout, а конкретная страница подставляется в Outlet. index-маршрут отдаёт главную по тому же пути, что и сам layout, — это ровно тот приём, который в реальных проектах экономит больше всего разметки.

src/App.js + src/components/layout.jsjsx
function App() {
    return (
        <Routes>
            <Route path="/" element={<Layout />}>
                <Route index element={<HomePage />} />
                <Route path="/about" element={<About />} />
                <Route path="/forms" element={<Forms />} />
            </Route>
        </Routes>
    );
}

const Layout = () => (
    <>
        <header className="flex justify-center">
            <Link className="mr-3" to="/">Home</Link>
            <Link className="mx-3" to="/about">About</Link>
            <Link className="mx-3" to="/forms">Forms</Link>
        </header>
        <Outlet />
    </>
);

Валидация формы с блокировкой отправки

Правила описаны рядом с полем, сообщения приходят из того же объекта состояния, кнопка отправки заблокирована пока форма невалидна. Для учебного проекта это ровно тот минимум, который показывает понимание контролируемых форм и режима валидации по blur.

src/components/forms.jsjsx
const { reset, register, formState: { errors, isValid }, handleSubmit } =
    useForm({ mode: "onBlur" });

<form onSubmit={handleSubmit(onSubmit)}>
    <input
        {...register("firstName", {
            required: "Поле обязательно к заполнению",
            minLength: { value: 5, message: "Минимум 5 символов" },
        })}
    />
    {errors?.firstName && <p>{errors.firstName.message}</p>}

    <input type="submit" disabled={!isValid} />
</form>

Что не доделано

Пишу сам, до того как заметит собеседующий.

  • Стилизация минимальная
  • Это упражнение, а не продукт — в наборе он для полноты картины