Next13のServer Actionsを使ってReact Hook Formとyupを使ってみる
事の発端
Next.jsのバージョンが13になって今までのNextからガラッと作り方が変わりそうと思ってたところに、「APIがいらなくなる」という話を耳にした。
なにやらServer Actionsなるものがあるらしい。
Server Actions
Next13.4はまだα版。
機能改善などは行われていたが、13.5でもα版から移行したことなどは書かれていなかった。
何はともあれ作ってみる
- Next13
- typescript
- react-hook-form
- yup
- prisma
prismaでcreateするとこまで。
※仕様一部省略 + type指定簡略化
Nextのプロジェクト作る
ドキュメントに沿ってプロジェクト作成。
npx create-next-app@latest
色々質問されるから自分の好みに合わせて作成。
configにserveraAtions
の設定を追加。
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
serverActions: true,
},
reactStrictMode: true,
};
module.exports = nextConfig;
prismaの準備
DBは簡単にDockerでpostgreを立ち上げた。
# とりあえず初期化
pnpm prisma init
# schemaをいじってマイグレーション
pnpm prisma migrate dev --name init
# generateする
pnpm prisma generate
ここらへん忘れずにやってとりあえずオッケー。
今回メインにやりたいとこでないのでパスワードとかも全部簡略化して作る。
model Users {
id String @id @default(uuid())
name String
email String
password String
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
}
登録フォーム作る
最近はfeatures
に機能ごとまとめることが多いのでfeatures/user
ディレクトリに作っていく。
src/
├─ app/
├─ features/
│ ├─ user/
│ │ ├─ ココ
├─ components/
# ...割愛
外側
今回はコンポーネント化もせずにそのまま作っちゃう。
'use client'
import { yupResolver } from '@hookform/resolvers/yup'
import { FC } from 'react'
import { useForm } from 'react-hook-form'
import { createUser } from '~/features/user/hooks/create'
import { userSchema } from '~/schemas/user'
const UserForm: FC = () => {
const {
register,
handleSubmit,
formState: { errors },
} = useForm({
mode: 'onSubmit',
resolver: yupResolver(userSchema),
})
const onSubmit = handleSubmit((data) => {
createUser(data)
})
return (
<form className='flex flex-col gap-4' onSubmit={onSubmit}>
<section className='flex flex-col'>
<label className=''>name</label>
<input className='rounded-md border border-gray-500 px-2 py-1' {...register('name')} />
{errors.name && <span className='text-xs text-red-500'>{errors.name.message}</span>}
</section>
<section className='flex flex-col'>
<label className=''>email</label>
<input className='rounded-md border border-gray-500 px-2 py-1' {...register('email')} />
{errors.email && <span className='text-xs text-red-500'>{errors.email.message}</span>}
</section>
<section className='flex flex-col'>
<label className=''>password</label>
<input className='rounded-md border border-gray-500 px-2 py-1' {...register('password')} />
{errors.password && <span className='text-xs text-red-500'>{errors.password.message}</span>}
</section>
<button type='submit' className='text-bold rounded-sm bg-orange-300 px-2 py-1'>
Add User
</button>
</form>
)
}
export default UserForm
"use client";
import { NextPage } from "next";
import UserForm from "~/features/user/UserForm";
const Home: NextPage = () => {
return (
<main>
<UserForm />
</main>
);
};
export default Home;
こんな感じ。
バリデーションできてるしいい感じ。
登録
今回のメインどころ。
prisma使ってDBへの登録処理するところ。
ここでAPIを使う必要がなくなるのはとても便利になった印象。
ただprismaのコードがあると違和感がすごいなぁ……本当に動くのか……。
'use server'
import prisma from '~/lib/prisma'
export const createUser = async (data: { name: string; email: string; password: string }) => {
'use server'
console.log(data)
await prisma.users.create({ data })
}
手間取ったときの参考にしたところ。
登録してみる
適当に入力してボタンぽち。
console.log出てる。
{ name: 'テスト', email: 'sample@email.com', password: 'passpass' }
DB見てみる。
おお、登録できた。
パスワードやらそのまま入れてるけど今回はこれでオッケーってことにする。
やってみて
結論:
とりあえずreact-hook-formとyupは動きはするっぽい。
Next13はまだ触りたてなのもあってclient側なのかserver側なのかの切り分けが難しいのと、formのaction使ってなかったりで動いてはいるけど実際想定通りの動きなのかはまた調べないといけない(一応サーバー側では動いてたけど)。
actionを使った実装だとどうなるのか、reack-hook-formをこれからも使っていくのであればよりドキュメントに沿って作れるようにこれからも試していく。
Discussion