MENU

React ChildrenとPropsの違いを確認

目的

PropsとChildrenの違いが曖昧だったので確認

結論

検証コード

Parentコンポーネントに Propsと childresを渡してみた

const Parent = ({ title, children }: { title:  string, children: React.ReactNode }) => {
  return (
    <>
      <p>{title}</p>l
      <p>{children}</p>
    </>
  )
}


const Child = () => {
  return (
    <>child</>
  )
}
const App = () => {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<Inputs>(formOptions);

  const handleFormData = (data: FieldValues) => {
    console.log(`FieldValues ${JSON.stringify(data)}`)

  }

  return (
    <>
    <Parent title={'Parent'}>
      <Child />
    </Parent>
  )
}
  • 結果

useFormのバリデーションはライブラリを利用するケースが多そうだ

背景

なんで yup 利用する必要があるのか疑問で少し調べた

useFormとyupなどのライライブラリの役割

useFormはformのstateを管理する事にフォーカスしている様子 yupなどはバリデーションなどを簡単に設定できる

yup

ライブラリでもyupがメジャーっぽい

Stringやnumberのチェックが簡単にできる

import React from "react"
import { useForm } from "react-hook-form"
import { yupResolver } from "@hookform/resolvers/yup"
import * as yup from "yup"

type Inputs = {
  name: string
  age: string
}

const schema = yup
  .object()
  .shape({
    name: yup.string().required(),
    age: yup.number().required(),
  })
  .required()

const App = () => {
  const { register, handleSubmit } = useForm<Inputs>({
    resolver: yupResolver(schema), // yup, joi and even your own.
  })

  return (
    <form onSubmit={handleSubmit((d) => console.log(d))}>
      <input {...register("name")} />
      <input type="number" {...register("age")} />
      <input type="submit" />
    </form>
  )
}

primsma 1対多 多対多のケース

目的

PrismaによるDB定義と、呼び出しの方法を 1対多、多対多で調べてみた

1対多

  • 定義
model User {
  id    Int     @id @default(autoincrement())
  name  String
  posts Post[]
}

model Post {
  id      Int     @id @default(autoincrement())
  title   String
  content String
  userId  Int
  user    User    @relation(fields: [userId], references: [id])
}
  • 呼び出し
  const user = await prisma.user.findUnique({
      where: { id: parseInt(userId) },
      include: {
        posts: true,
      },
    });

多対多

  • テーブル定義
model User {
  id    Int      @id @default(autoincrement())
  name  String
  posts Post[]   @relation("UserToPost", references: [id])
}

model Post {
  id      Int      @id @default(autoincrement())
  title   String
  content String
  users   User[]   @relation("UserToPost", references: [id])
}

model UserToPost {
  id      Int      @id @default(autoincrement())
  userId  Int
  postId  Int
  user    User     @relation(fields: [userId], references: [id])
  post    Post     @relation(fields: [postId], references: [id])
  @@unique([userId, postId]) 
}
  • 呼び出し
    const user = await prisma.user.findUnique({
      where: { id: parseInt(userId) },
      include: {
        posts: true,
      },
    });
  • ユーザーがポストする場合の処理

中間テーブルを作成する方法は2つあるらしい

### パターン1

    // 1. ポストを作成
    const post = await prisma.post.create({
      data: {
        title,
        content,
      },
    });

    // 2. ポストとユーザーを関連付ける
    await prisma.userToPost.create({
      data: {
        userId: parseInt(userId),
        postId: post.id, // 新しく作成したポストのIDを使用
      },
    });

### パターン2
await prisma.user.update({
  where: { id: parseInt(userId) },
  data: {
    posts: {
      connect: { id: parseInt(postId) }, // 既存のポストを関連付ける
    },
  },
});

テーブル設計 基本

目的

テーブル設計する時にいつも忘れるので、ポイントをメモ

流れ

  • エクセルなどで管理されていることが大半
  • 表で書かれているものを分割していく
顧客ID 顧客名   担当者名    メールアドレス 商品                        注文日
xxxx    テスト会社 山田  xxxx@aaa.aa "商品A × 3 商品B × 3" 2023/09/08
  • 1対多になるか、多対多になるか判定していく

実際にやる

  1. 分割 & 1対多になるか、多対多になるか

顧客と注文が1対多で、注文と商品が多対多になりそう

■顧客
・ID
・顧客名
・顧客ID

■担当者
・ID
・担当者名
・メールアドレス
・顧客_id

■商品
・ID
・商品名
・価格

■注文
・ID
・担当者_id
・注文合計金額

■注文商品
・注文_id
・商品_id

よく悩むポイント

  • 1対多の多の方に1の外部キーを入れる

nest js + docker + prisma を実装してみる

できること

nest js, primsa, mysql をdockerで構築する

手順

  1. nest をローカル環境に入れる
  2. dockerfile, docker-composeを作成
  3. prismaを入れる

完成コード

  • dockerfile
FROM node:18 as base

WORKDIR /app

# * で lockもか
COPY package*.json ./
RUN npm i
COPY . .

RUN npm run build

FROM base as dev

WORKDIR /app
COPY package*.json ./
RUN npm install

CMD ["npm", "run", "start:dev"]
  • docker-compose
version: '3'
services:
  backend:
    build:
      context: .
    volumes:
      - ./:/app
    ports:
      - 3001:3001
    depends_on:
      - mysql
    networks:
    - backend
  mysql:
    image: mysql:8.0.27
    platform: linux/amd64
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: mysql
      MYSQL_DATABASE: todo_app_db
      MYSQL_USER: user
      MYSQL_PASSWORD: password
    restart: always
    networks:
    - backend
networks:
  backend:

詰まったこと

  1. docker-composeで nestjs と mysqlを接続するときに、networkを設定しないといけない

これは、下記で作成する場合、デフォルトではコンテナごとに別のネットワークを構築するらしい

version: '3'
services:
  backend:
    build:
      context: .
    volumes:
      - ./:/app
    ports:
      - 3001:3001
    depends_on:
      - mysql
  mysql:
    image: mysql:8.0.27
    platform: linux/amd64
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: mysql
      MYSQL_DATABASE: todo_app_db
      MYSQL_USER: user
      MYSQL_PASSWORD: password
    restart: always

なので下記のように networkを作成する必要がある

version: '3'
services:
  backend:
    build:
      context: .
    volumes:
      - ./:/app
    ports:
      - 3001:3001
    depends_on:
      - mysql
    networks:
    - backend
  mysql:
    image: mysql:8.0.27
    platform: linux/amd64
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: mysql
      MYSQL_DATABASE: todo_app_db
      MYSQL_USER: user
      MYSQL_PASSWORD: password
    restart: always
    networks:
    - backend
networks:
  backend:
  1. prismaマイグレーションができない

下記の様にすべての権限をユーザーにあげないと、 migrateできなかった

grant all CREATE, ALTER, DROP, REFERENCES ON *.* to prisma_user@localhost;
  1. docker内で nest と mysqlの環境を作る場合のmysqlのホスト

下記のprisma様に設定した様に、docker-compose で設定した様に、 mysqlになるみたい

DBだけ docker化した場合はhost はlocalhostだった

DATABASE_URL="mysql://user:password@mysql:3306/todo_app_db?schema=public"
  1. コンテナ内のdb接続
## 接続
docker-compose exec mysql bash

mysql -u root -p
※ MYSQL_ROOT_PASSWORDの内容で入る


## 権限状態を確認
SHOW GRANTS FOR 'user'@'%' ;
  1. M1 Mac で docker 利用のmysqlの設定でplatformの設定が必要

m1はこういうのがちょこちょこあるよね

  mysql:
    image: mysql:8.0.27
    platform: linux/amd64
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: mysql
      MYSQL_DATABASE: todo_app_db
      MYSQL_USER: user
      MYSQL_PASSWORD: password
    restart: always
    networks:
    - backend

参考サイト

  • nest js docker化

qiita.com

  • nest jsにprismaを入れる

qiita.com

  • primsa migrateの権限エラー対応

zenn.dev

docker マルチステージビルドをNext.js でやってみた

目的

最近では、AWSなどのインフラを設定するときに、 dockerがマストになってきていて、AWSはECSの利用、GCPの場合Cloud Runでコンテナを利用してdockerの扱いに慣れる必要があるなと思い取り組んでみました

必要性

dockerを利用した開発において、開発環境、テスト環境、本番環境をdocker で管理する場合、dockerfileを分けるケースがありました

ただその場合のデメリットとして下記があるかなと感じました。

  • 保守性が悪い 例えば、開発環境で新しいライブラリを入れたら、 テスト環境、本番環境のdockerfileを編集しないといけない

  • DRYでない ベース imageなどの重複したコードになる

マルチステージビルド

マルチステージビルドでは、これが解消できそう

特徴は下記かなと思う - as を利用してステージ(環境、ステップを分ける) - --from= を利用して、別ステージの要素を引き継げる

  • 利用方法
## 利用したいステージで buildする

docker build -t prod-front --target prod .  

## 実行する
docker run prod-front -p 3000:3000

完成したコード

# ビルド イメージを設定
FROM node:18.12-alpine AS base

# 作業ディレクトリを設定
WORKDIR /app

# 依存関係をコピーしてインストール
COPY package.json package-lock.json ./
RUN npm install

# アプリケーションのソースコードをコピー
COPY . .
RUN npm run build

# dev ステージを追加
FROM node:18.12-alpine AS dev

# 作業ディレクトリを設定
WORKDIR /app

# 依存関係をコピー
COPY package.json package-lock.json ./
RUN npm install

# アプリケーションのソースコードとビルドアーティファクトをコピー
COPY --from=base /app/.next ./.next
COPY --from=base /app/public ./public

# アプリケーションを開発モードで実行
CMD ["npm", "run", "dev"]

# 本番用のイメージを作成
FROM node:18.12-alpine AS prod

# 作業ディレクトリを設定
WORKDIR /app

# 依存関係をコピー
COPY package.json package-lock.json ./
RUN npm ci --only=production

# アプリケーションのソースコードとビルドアーティファクトをコピー
COPY --from=base /app/package.json package.json
COPY --from=base /app/.next ./.next
COPY --from=base /app/next.config.js next.config.js
COPY --from=base /app/node_modules node_modules
COPY --from=base /app/public ./public

# アプリケーションを本番モードで実行
CMD ["npm", "run", "start"]