Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Действия и формы

Действие (action) — функция, которую модуль маршрута экспортирует под именем action. Она выполняется на сервере, когда на адрес маршрута отправляют форму методом POST (или PUT, PATCH, DELETE). Отправляют такую форму компонентом Form — это обычный тег form, которому фреймворк добавляет отправку без перезагрузки страницы.

Функция сохранения

Допишите в app/data.server.ts функцию добавления статьи:

// app/data.server.ts
export async function createPost(title: string, body: string) {
  const post: Post = { id: posts.length + 1, title, body };
  posts.push(post);
  return post;
}

Страница с формой

Добавьте маршрут route("posts/new", "routes/new-post.tsx") и создайте файл:

// app/routes/new-post.tsx
import { Form, redirect } from "react-router";
import type { Route } from "./+types/new-post";
import { createPost } from "../data.server";
 
export async function action({ request }: Route.ActionArgs) {
  const formData = await request.formData();
  const title = String(formData.get("title"));
  const body = String(formData.get("body"));
 
  const post = await createPost(title, body);
  return redirect(`/posts/${post.id}`);
}
 
export default function NewPost() {
  return (
    <Form method="post">
      <input name="title" placeholder="Заголовок" />
      <textarea name="body" placeholder="Текст статьи" />
      <button type="submit">Опубликовать</button>
    </Form>
  );
}

Откройте http://localhost:5173/posts/new, заполните поля и нажмите «Опубликовать». Форма уйдёт на тот же адрес, сработает action, и redirect откроет страницу новой статьи. Вернувшись на главную, вы увидите статью в списке.

Как это работает

  1. Form перехватывает отправку и посылает данные на сервер запросом POST.
  2. На сервере вызывается action, request.formData() возвращает поля формы по атрибутам name.
  3. После action фреймворк заново вызывает загрузчики страницы — данные на экране всегда свежие.
  4. redirect из react-router отвечает переходом на другой адрес.

Без JavaScript форма тоже работает: браузер отправит её обычным способом, а сервер ответит перенаправлением.

Ссылка на форму

На главной добавьте ссылку на новую страницу:

// app/routes/home.tsx
<Link to="/posts/new">Написать статью</Link>

Форма на другой адрес

Атрибут action у Form указывает, какой маршрут обработает отправку. Например, кнопку удаления можно разместить на странице статьи:

// app/routes/post.tsx
<Form method="post" action={`/posts/${post.id}/delete`}>
  <button type="submit">Удалить</button>
</Form>

Нужен маршрут posts/:postId/delete с функцией action; компонент ему не обязателен.

Частая ошибка

Поле без атрибута name не попадает в formData: formData.get("title") вернёт null, а String(null) превратится в строку "null" — именно она и окажется заголовком статьи. Проверяйте, что у каждого поля есть name, совпадающее с ключом, который читает action.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.