はじめに
こんにちは、torihaziです
週末リリース予定ですが、果たして終わるのでしょうか。
今日も時間は短いですが、やっていきましょう
技術選定
[frontend]
- Nextjs(pages router) => App Routerの理解に苦しんだため
- MUI => 調べたランキングでtopだったため(=> approuter では動かないそう。今後は要検討)
- react-hook-form => フォーム管理と言ったらこれでは?
- zod => 少しだけ使い慣れてるから
- axios => httpリクエスト送るのはこれでは?
- recoil => 状態管理、useStateのような扱いで使いやすい
- js-cookie => cookieを扱う上で使用。軽く、更新も頻繁にされている
- useSWR => データ取得用、
- Editorjs => WYSIWYGエディタ、学習のため導入。本サービスのキモ。
[backend]
- Rails 7 => 使い慣れているため
- devise => 定番だから
- devise-jwt => devise-token-authが古いらしいのでこっち
- letter_opener_web => 開発環境で確認メール確認用
[github]
続き
昨日は新規作成のところまで行きました
今日は日記のタイトルがまだformとして送信できないので今日はそこをやっていこうと思います
このuseSWRのfetcher、関数ににして外に括り出したほうがいいかも。
newするときのbound mutateの時に使いたいんだけど、これだと使えないや。
// // create // export const createInputScheema = z.object({ title: z.string().min(1, "Required"), content: z.string().nullish(), }); export type createInputSchemaType = z.infer<typeof createInputScheema>; export const postNewDiaryInput = async ( data: createInputSchemaType ): Promise<Diary> => { const newData = { diary: { ...data } }; return api.post("/api/v1/diaries", newData); }; export const useCreateDiary = ({ onSuccess, onError, }: { onSuccess?: () => void; onError?: () => void; }) => { const setSnackBarState = useSetRecoilState(snackbarAtom); const { data: diaries, mutate } = useSWR("/api/v1/diaries", getDiaries); const createDiary = async (data: createInputSchemaType) => { try { const newDiary = await postNewDiaryInput(data); mutate(); setSnackBarState(successState("作成しました")); if (onSuccess) { onSuccess(); } return newDiary; } catch (err) { setSnackBarState(errorState("エラー")); if (onError) { onError(); } throw err; } }; return { createDiary }; };
こんな感じに落ち着いたんだけどどうだろうか。
んー、なんか作成しましたのtoastは出るんだけど、あれだな。
ダメだ。
あたりまえだ。まだバックエンド作ってないや。
でもそしたらエラーに行ってくれないと困るんだけど。
なんで。
まぁいいか。
とりあえずbackendもできた。
def create diary = current_api_v1_user.diaries.build(diary_params) if diary.save render json: diary, status: :ok else error_messages = diary.errors.full_messages.join(',') render json: {message: error_messages}, status: :unprocessable_entity end end
一応、タイトルのところだけは formで囲んで、Editorはeditorだけで独立させた。
でreact-hook-formの管轄はタイトルだけだけど、submitする時に
editorのdataをくっつけて一緒に送る感じ。
import { DiaryTemplate } from "@/components/template/DiaryTemplate"; import { DiaryTitleForm } from "@/features/diaries/components/diary-title-form"; import { createInputScheema, createInputSchemaType, useCreateDiary, } from "@/lib/api/diaries"; import { OutputData } from "@editorjs/editorjs"; import { zodResolver } from "@hookform/resolvers/zod"; import { Button } from "@mui/material"; import dynamic from "next/dynamic"; import { useRouter } from "next/router"; import { useState } from "react"; import { SubmitHandler, useForm } from "react-hook-form"; const Editor = dynamic(() => import("@/features/editorjs/editor-js"), { ssr: false, }); const DiaryNew = () => { const [outputData, setOutputData] = useState<OutputData | null>(null); const router = useRouter(); const { createDiary } = useCreateDiary({ onSuccess: () => { router.push("/diaries"); }, }); const form = useForm<createInputSchemaType>({ mode: "onChange", resolver: zodResolver(createInputScheema), }); const onValid: SubmitHandler<createInputSchemaType> = ( data: createInputSchemaType ) => { const newData = { ...data, content: JSON.stringify(outputData), }; createDiary(newData); }; return ( <DiaryTemplate> <DiaryTitleForm control={form.control} id="new-diary-title" /> <Editor value={outputData} onChange={setOutputData} holder="editorjs" /> <Button type="submit" form="new-diary-title" onClick={form.handleSubmit(onValid)} disabled={!form.formState.isValid} > 保存する </Button> </DiaryTemplate> ); }; export default DiaryNew;
このonValidのとこ。
で。
登録はできた。できたけど。
忘れてた。そうだった。contentを表示させるとこうなるのか。
どうするかな。
dataをやりくりして、なんとかして文字列に書き起こしてここに表示。
んー。そこまでやる必要あるかな。
ここのcontent消していいんでは?
消すか。
ていうかeditorjs の内容、空で送ったらnullになるんだけど。
あれかinitialなdataでもつけるようにするか。
というかなんかeditorjsの内容送られなくなった。
あれ、どこか変えたかな。
あーあれか
const onValid: SubmitHandler<createInputSchemaType> = ( data: createInputSchemaType ) => { const newData = { ...data, content: outputData === null ? JSON.stringify(outputData) : "", <= ここ }; createDiary(newData); };
多分ここ。outputDataが空白でもnullになることはない。
空なら
{ time: Date.now(), blocks: [], version: "2.30.6", };
こんな空ではないデータが飛ぶから。
やっぱり。治したらうまく行った。
で、
import { OutputData } from "@editorjs/editorjs"; export const INITIAL_EDITOR_DATA: OutputData = { time: Date.now(), blocks: [], version: "2.30.6", };
あらかじめこれを
const [outputData, setOutputData] = useState<OutputData>(INITIAL_EDITOR_DATA); const router = useRouter(); const { createDiary } = useCreateDiary({ onSuccess: () => { router.push("/diaries"); }, }); ~~~
このuseStateの初期値にsetする。
これなら、空として送信してもnullにならないのでは?
OK。blocksが[]になってる。
あとはここに表示させる時になんとかしよう。
これで新規作成終了。多分ね。次は更新か。
終わりに
寝てました。すいません。