Next.jsの歩き方


変更からデプロイまで

1.ローカルテスト
npm run dev
2.コードのステージング
git add .
3.リポジトリにコミット
git commit -m "説明文"
4.リモートリポジトリにプッシュ
git push
5.本番にデプロイ
vercel --prod


Next.js (JavaScript/TypeScript) に Chakra UI を導入する方法
chakra-ui


TypeScriptの導入


途中から追加する場合
・ルートにtsconfig.jsonを作成
・TypeScriptとその他の必要なtypesをインストール

npm install --save typescript @types/node @types/react @types/react-dom @types/jest

・tsconfig.jsonが更新されている事の確認。
・.jsを.tsxに変更して動作する事の確認。

useEffect

マウント時に一回だけ実行
useEffetctに渡されるコールバック関数を、コンポーネントのマウント時に1回だけ実行するには、第2引数に空の配列を渡します。

useEffect(() => { ... }, []);

useEffectの第2引数に配列を渡すと、マウント時とその要素に変更があった場合にコールバック関数を実行するように動作します。
例えば何らかのidに変更があった場合に、API通信してデータを取得する、などの使い方ができます。

const [id, setId] = useState(0);
useEffect(() => { ... }, [id]); // idに変更があった場合に、コールバック関数を実行する。


プログレスバー

npm install nextjs-progressbar

/pages/_app.tsx

import NextNprogress from 'nextjs-progressbar' 

<NextNprogress />

nextjs-progressbar

CSS

import styles from "../../styles/home.module.scss";

<div className={styles.contain}></div>

複数の場合

<div className={`${styles.class1} ${styles.class2}`}></div>

html内で直接スタイルを書く

<div style={{ backgroundColor: `lightGray` }} ></div>


キーボードイベント

const handleKeyDown = (event: KeyboardEvent) => {
  // Escapeキーの場合処理を行う
  if (event.key === "Escape") {
    console.log("keydown Escape Key");
  }
};
useEffect(() => {
  document.addEventListener("keydown", handleKeyDown, false);
}, []);


oauth接続

npm info next version = 12.1.6

//pages/api/auth/[...nextauth].js
import axios from "axios";
import NextAuth from "next-auth";
import GithubProvider from "next-auth/providers/github";
import GoogleProvider from "next-auth/providers/google";
import { signIn } from "next-auth/react";

// prisma adaptor 使って、user データ、認証データを永続化する
// import { PrismaAdapter } from "@next-auth/prisma-adapter";
// import { PrismaClient } from "@prisma/client";
// const prisma = new PrismaClient();

const { GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, NEXT_PUBLIC_SECRET } =
  process.env;
// if (!GOOGLE_ID) throw new Error("You must provide GOOGLE_ID env var.");
// if (!GOOGLE_SECRET) throw new Error("You must provide GOOGLE_SECRET env var.");

const setting = {
  // adapter: PrismaAdapter(prisma),
  providers: [
    GoogleProvider({
      clientId: GOOGLE_CLIENT_ID,
      clientSecret: GOOGLE_CLIENT_SECRET,
    }),
  ],
  callbacks: {
    async signIn({ user, account, profile, email, credentials }) {
      console.log("サインイン");
      return true;
    },
    async jwt({ token, user, account, profile, isNewUser }) {
      console.log(`アカウント:${JSON.stringify(account)}`);
      return token;
    },
  },
  // callbacks: {
  // emailのドメイン制限を入れたい場合は以下のcallbacksを入れてください
  // signIn: async (user, account, profile) => {
  //   if (
  //     account.provider === "google" &&
  //     profile.verified_email === true &&
  //     profile.email.endsWith("@example.com")
  //   ) {
  //     return Promise.resolve(true);
  //   } else {
  //     return Promise.resolve(false);
  //   }
  // },
  // },
  // ここに NEXTAUTH_SECRET を入れる?
  secret: NEXT_PUBLIC_SECRET,
};

export default (req, res) => NextAuth(req, res, setting);


nextauthでprisma.adapterを使う場合はschema.prismaに下記が必要
※prisma.adapterを使えばログイン情報が自動保存される
※nextauthの公式と違うのが気になるけど試してない 公式

model Account {
  id                String  @id @default(cuid())
  userId            String  @map("user_id")
  type              String
  provider          String
  providerAccountId String  @map("provider_account_id")
  refresh_token     String? @db.Text
  access_token      String? @db.Text
  expires_at        Int?
  token_type        String?
  scope             String?
  id_token          String? @db.Text
  session_state     String?

  user User @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([provider, providerAccountId])
  @@map("accounts")
}

model Session {
  id           String   @id @default(cuid())
  sessionToken String   @unique @map("session_token")
  userId       String   @map("user_id")
  expires      DateTime
  user         User     @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@map("sessions")
}

model User {
  id            String    @id @default(cuid())
  name          String?
  email         String?   @unique
  emailVerified DateTime? @map("email_verified")
  image         String?
  accounts      Account[]
  sessions      Session[]

  @@map("users")
}


開発用env
.gitignoreに含めてアップしないようにする

//.env.local
コマンド叩いて値を取る
NEXT_PUBLIC_SECRET=# Linux: `openssl rand -hex 32` or go to https://generate-secret.now.sh/32

NEXTAUTH_URL=http://localhost:3000

こっちがfirebase
GOOGLE_CLIENT_ID=xxx
GOOGLE_CLIENT_SECRET=xxx


本番用env
Vercelなどのホスティングサービスにアップする

参考サイト
NextAuth.jsを使ったGoogle認証機能+データベース(Prisma)の設定の理解
NextAuth.js公式フロー

Twitterの認証
readmeに記入

無限スクロール

import {useState} from 'react';
import InfiniteScroll  from "react-infinite-scroller"

export default function Index() {
  const [list, setList] = useState([]);          //表示するデータ
  const [hasMore, setHasMore] = useState(true);  //再読み込み判定
  
    //項目を読み込むときのコールバック
    const loadMore = async (page) => {
      
      const response = await fetch(`http://localhost:3000/api/test?page=${page}`);  //API通信
      const data = await response.json();  //取得データ

      //データ件数が0件の場合、処理終了
      if (data.length < 1) {
        setHasMore(false);
        return;
      }
      //取得データをリストに追加
      setList([...list, ...data])
    }

  //各スクロール要素
  const items = (
    <ul>
      {list.map((value) => <li>{value}</li>)}
    </ul>);
  
  //全体のスタイル
  const root_style = {
    marginLeft : "50px",
    marginTop : "50px",
  }

  //ロード中に表示する項目
  const loader =<div className="loader" key={0}>Loading ...</div>;

  return (
    <div style={root_style}>
      <InfiniteScroll
        loadMore={loadMore}    //項目を読み込む際に処理するコールバック関数
        hasMore={hasMore}      //読み込みを行うかどうかの判定
        loader={loader}>      {/* 読み込み最中に表示する項目 */}

          {items}             {/* 無限スクロールで表示する項目 */}
      </InfiniteScroll>
    </div>
  )
}





GOOGLE_CLIENT_SECRET=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