Next.js サービス開発メモ2
別サービスを作り始めたので作業記録用
・Vercel + Firebase 構成
・CSSフレームワークは Bootstrap(開発速度重視)
早速 Firebase init ではまった
firebase logout → login にて既存プロジェクト取得できた。こっちはロケーション設定を再度入れて直った
.firebaserc
firebase.json
firebase.indexes.json
firebase.rules
まで出力できた。記述を入れて deploy する予定
strage.rules は名前が名前だからかVSCode上でアイコンがつかないな…まぁいいけど
React-Bootstrap Navbar で Dropdown を展開するとエラー
React-Bootstrap の Navbar で Dropdown を使うと初回このエラーがでる
Warning: validateDOMNesting(...): <a> cannot appear as a descendant of <a>.
at a
at LinkComponent (webpack-internal:///./node_modules/next/dist/client/link.js:105:19)
at a
Navbar.Item は Aタグを持っているようなのでタグ内にNextのLinkタグを入れるとこのエラーが出るっぽい。最近 <a>タグいらなくなったことと関連しているかな?
Navbar.Item → Navbar.ItemText でエラーは消えたっぽいのでこれで様子見
ItemText だと文字の範囲内しかリンクが変わらないので暫定でこの記述にした。
<NavDropdown.ItemText>
<Link href="/links">
<div className="w-100">リンク</div>
</Link>
</NavDropdown.ItemText>
Nav.Link 使えよ!みたいなやりとりがあるがいまいち上手くいかないのでこちらは保留
Vercel でコンパイルエラーが出る
突然コンパイルエラーが出て Vercel を通らなくなった。
Failed to compile.
./src/pages/_app.tsx:32:10
Type error: 'Component' cannot be used as a JSX component.
Its element type 'ReactElement<any, any> | Component<any, any, any> | null' is not a valid JSX element.
Type 'Component<any, any, any>' is not assignable to type 'Element | ElementClass | null'.
Type 'Component<any, any, any>' is not assignable to type 'ElementClass'.
The types returned by 'render()' are incompatible between these types.
Type 'React.ReactNode' is not assignable to type 'import("/vercel/path0/node_modules/@types/react-transition-group/node_modules/@types/react/ts5.0/index").ReactNode'.
Type 'ReactElement<any, string | JSXElementConstructor<any>>' is not assignable to type 'ReactNode'.
Property 'children' is missing in type 'ReactElement<any, string | JSXElementConstructor<any>>' but required in type 'ReactPortal'.
30 | />
31 | <RecoilRoot>
> 32 | <Component {...pageProps} />
| ^
33 | </RecoilRoot>
34 | </>
35 | )
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
Error: Command "yarn run build" exited with 1
@types/react のバージョンが噛み合わなくなってるっぽい?
"resolutions": {
"@types/react": "17.0.40"
},
この記述で通るようにはなった。
17のどのバージョン書けばいいのか今の正解探さないと…
突然 ReactーBootstrap が cannot be used as a JSX component を吐き倒す
yarn add --dev @types/react-dom
これで回避、なんでや
その後も @types/react @types/react-dom あたりを最新(v18)にすると同様のエラーを吐くようになった。package.json の resolution 設定やバージョンダウンで回避していたが面倒になったので React-Bootstrap を完全除去した。その方が楽
React-Hook-From を Zod でバリデーションする
React-Hook-From の内蔵機能でバリデーションしていたが Zod に切り替えする。
業務に直結する部分でややこしい記述を公開されがちなので分かりやすいものを探す。
なんとなく書き方がわかったので公式を読むぜ〜
zod と @hookform/resolvers が必要
エラーメッセージを
{errors.body && ({errors.body.message})
で受けようとすると以下のエラーが表示される
型 'string | FieldError | Merge<FieldError, FieldErrorsImpl<any>> | undefined' を型 'ReactNode' に割り当てることはできません。
型 'FieldError' を型 'ReactNode' に割り当てることはできません。
型 'FieldError' には 型 'ReactPortal' からの次のプロパティがありません: children, props, keyts(2322)
index.d.ts(1466, 9): 予期された型は、型 'DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>' に対してここで宣言されたプロパティ 'children' から取得されています
(property) message?: string | FieldError | Merge<FieldError, FieldErrorsImpl<any>> | undefined
これで回避できたけどこれでいいのか?
{errors.body && ({errors.body.message as string})
とりあえず動いたので次、チェックが入っていると次の入力欄を必須にしたい。
React-Hook-From 純正機能でめんどくさくてやめたやつ。
Zod の Union 機能でいけそう
たぶんこの分野深いw ので浅い部分をすくい取ってとりあえず実装したい
union だと超煩雑になる? refine の方がいいか?
やっぱ union の方がいいか?w
バリデーションの定義が結合できると知ったw
値が入っているかどうかは string() のカッコ内だったか…今更w
Union ではなく discriminatedUnion を使った。
基本部分のスキーマと条件分岐するスキーマに分けて最後に結合して export で多分正常動作
次、ファイルアップロード部分の Validation 実装
transform か … こういうのも使えそうか … 覚えとこ
ファイルアップロード部分の Validation がうまく動かんなぁ
const fileSchema = z.object({
file: z
.custom<FileList>()
.refine((files) => {
}
})
これであとはなんとかなるか
.transform((file) => file[0])
ファイルを1つにしてしまえば楽なんでこの処理が多い
複数ファイルの処理の過程でいくつかのエラー処理をするためにMap関数を回していると2次元配列になってしまうので1次元配列に戻す方法
なーほーねrefine だと 返せるエラーは1つだけになるのか
superRefine 使えと、よく読めば前に見たこれに書いてある … 神!
.refine は一つの項目のバリデーションエラーしか指定できませんが、 .superRefine は .addIssue を複数回呼び出すことで、複数の項目に渡ってバリデーションエラーを指定することができます。
これでいけるかな?
const photoSchema = z
.object({
photos: z.custom<FileList>(),
})
.superRefine(({ photos }, ctx) => {
const files = Array.from(photos)
let message: string[] = []
files.map((file) => {
if (file.size > MAX_FILE_SIZE) {
message.push(
`ファイルサイズが大きすぎます。${MAX_MB}MB以下のファイルを選択してください [${file.name}]`,
)
}
if (!ACCEPTED_IMAGE_TYPES.includes(file.type)) {
message.push(`jepg, jpg, png, webpのいずれかの画像を選択してください [${file.name}]`)
}
})
if (message.length > 0) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: message.join(`\n`),
path: ['photos'],
})
}
})
INPUTタグの onChange イベントに setValue つけてなかったので別のトラブル引き起こしてたので追加した。
ブログなどによくあるタグの入力フォームを作りたいけど良い部品ないなぁ
事例も少なさそうで手作りが多いんかな?
アップロードファイルの情報をデータベース側にも保存する
フォームから取得できる FileList 形式から配列を作り直して入れたい。
Firebaseの接続でエラー
なんかエラー吐き倒してんなと思ったらこれだった
// databaseURL: process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL,
この項目無くなってたんやね…
HTMLでIncorrect use of <label for=FORM_ELEMENT>
name で指定した値を htmlFor に入れるように部品を修正して対応した
プロパティを変数にして共通部品化したい場合
hogehoge[aaaa].prop
でいける
Toast 表示後に router.push で消えてしまう問題
これで解決らしい
Third-party cookie will be blocked. Learn more in the Issues tab.
コンソールでこのエラーが出続ける(表示される)ようになった
Third-party cookie will be blocked. Learn more in the Issues tab.
原因は Fireabase Auth かな?
Firestore の (アンダーバーx2)name(アンダーバーx2)
インデックス作成時に沸いてきたけど何これ?
Firebase Auth のログインと 3rd-Party Cookie 問題
記事中にあったこの辺も読みながら対応を考える
3rd Party Cookie は Google がモリモリ進めてるけど Firebase は対応に苦慮している感じ
App Router 化でもどうしよっかなみたいな気分になっていてFirebaseから離脱しようかなとか漠然と考えているのが今
Google Analytics v4 への移行
楽ちんやで
FullCalendar v6 アップデート
長い間 v6 を避けていたのでアップデートを実行
<FullCalendar
// 中間省略
dayCellContent={(event: DayCellContentArg) => {
return (event.dayNumberText = event.dayNumberText.replace('日', ''))
}}
/>
return を入れないと日付が表示されなくなっていた…まぁそうなんだけど
import { EventClickArg, DayCellContentArg } from '@fullcalendar/core'
あとは上2つの値の参照先が変わっていた