把 nextjs netflix clone 教程学完了

·

3 min read

跟着教程,一个半月时间,67个半小时。终于学完了。代码跟着写了一遍,注册登录部分只写了登录。在这里做一些零碎的总结,算是收尾了。

  // zustand, 全局状态管理工具。状态变了,使用状态的组件会更新
  const {openModal} = useInfoModalStore()
import useSwr from 'swr'
import fetcher from '@/libs/fetcher';

const useBillboard = () => {
  // swr,2秒内发送同一个请求,只发一个
  // 缓存和请求校验,相同,组件不更新
  const { data, error, isLoading } = useSwr('/api/random', fetcher, {
    revalidateIfStale: false,
    revalidateOnFocus: false,
    revalidateOnReconnect: false,
  });
  return {
    data,
    error,
    isLoading
  }
};

export default useBillboard;
import { PrismaClient } from '@prisma/client'

// prisma
// 数据库orm
// 数据库 schema,数据库表设计
// 数据库迁移
// 相当于在数据库查询语句上做一层抽象,屏蔽到不同数据查询语句sql的差异。
// 还有数据库迁移、初始化等功能
const client = global.prismadb || new PrismaClient()
if(process.env.NODE_ENV !== 'production') global.prismadb = client

export default client
import { authOptions } from "@/pages/api/auth/[...nextauth]";
import { NextApiRequest, NextApiResponse } from "next";
import { getServerSession } from "next-auth";

// 身份验证,以及身份信息获取
const serverAuth = async (req: NextApiRequest, res: NextApiResponse) => {
  const session = await getServerSession(req, res, authOptions)

  if(!session?.user?.email) {
    throw new Error('Not signed in')
  }

  const currentUser = await prismadb.user.findUnique({
    where: {
      email: session.user.email,
    }
  })

  if(!currentUser) throw new Error('Not signed in')

  return {currentUser}

}

export default serverAuth
// index.tsx
import Navbar from "@/components/Navbar";
import Billboard from '@/components/Billboard';
import MovieList from '@/components/MovieList';
import useInfoModalStore from '@/hooks/useInfoModalStore';
import InfoModal from '@/components/InfoModal';
import { NextPageContext } from "next";
import { getSession } from "next-auth/react";
import useMovieList from "@/hooks/useMovieList";
import useFavorites from "@/hooks/useFavorites";

// 在node环境下运行,浏览器没办法 debug 这部分内容
export async function getServerSideProps(context: NextPageContext) {
  const session = await getSession(context)
  console.log(session);

  // 拦截页面跳转,没有session,跳转到登录页面
  if (!session) {
    return {
      redirect: {
        destination: '/auth',
        permanent: false,
      }
    }
  }

  return {
    props: {}
  }
}

export default function Home() {
  const  {data: movies=[]} = useMovieList()

  const {data: favorites=[]} = useFavorites()

  // 两兄弟组件共用状态放在 zustand 管理起来,逻辑挺清楚的。
  // 写起来麻烦些。
  // 之前那种父组件向子组件传参,调用组件内方法。
  // 子组件向父组件传参,emit 自定义事件也挺麻烦的,并且耦合深,不通用
  const { isOpen, closeModal } = useInfoModalStore()




  return (
    <>
      <InfoModal visible={isOpen} onClose={closeModal}/>
      <Navbar></Navbar>
      <Billboard></Billboard>
      <div className="pb-40 pl-[47px] bg-black">
        <MovieList title="Trending Now" data={movies}></MovieList>
        <MovieList title="My List" data={favorites}></MovieList>
      </div>
    </>
  )
}

本地起 mongodb 以及应用连接 mongodb 花了挺多时间。连接上之后,发现第三方登录还是不行。最后跟着视频教程用 mongodb atlas 。

nextjs 基于react 的全栈框架,包含路由、请求、打包、优化等 nextjs 默认使用 server component,使用服务端渲染

tailwindcss
self-center 交叉轴居中
appearance-none 移除默认样式

flex 子元素 右对齐
子元素设置 ml-auto

nextjs,服务端渲染,服务端直接生成html发给浏览器。 客户端渲染,发html,发js库,发js,浏览器渲染。

// schema.prisma
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
  provider = "prisma-client-js"
  previewFeatures = ["mongoDb"]
}

datasource db {
  provider = "mongodb"
  url      = env("DATABASE_URL")
}

model User {
  id String @id @default(auto()) @map("_id") @db.ObjectId
  name String
  image String?
  email String? @unique
  emailVerified DateTime?
  hashedPassword String?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  sessions Session[]
  accounts Account[]
  favoriteIds String[] @db.ObjectId
}

model Account {
  id String @id @default(auto()) @map("_id") @db.ObjectId
  userId             String   @db.ObjectId
  type               String
  provider           String
  providerAccountId  String
  refresh_token      String?  @db.String
  access_token       String?  @db.String
  expires_at         Int?
  token_type         String?
  scope              String?
  id_token           String?  @db.String
  session_state      String?

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

  @@unique([provider, providerAccountId])
}

model Session {
  id String @id @default(auto()) @map("_id") @db.ObjectId
  sessionToken String @unique
  userId String @db.ObjectId
  expires DateTime
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}

model VerificationToken {
  id String @id @default(auto()) @map("_id") @db.ObjectId
  identifier String
  token      String   @unique
  expires    DateTime

  @@unique([identifier, token])
}

model Movie {
  id String @id @default(auto()) @map("_id") @db.ObjectId
  title String
  description String
  videoUrl String
  thumbnailUrl String
  genre String
  duration String
}
prisma schema
User数据集
唯一 unique
id自动生成
可填/必填
default 默认值
@id 主键
@db.ObjectId 在数据库中使用 ObjectId 类型
Session[] 一个用户可以多个会话记录

Account 
账户类型,email Oauth
提供者google
Authorization:Bearer 接口请求,用于身份验证
一个账户与一个用户关联,用户被删除,账户也被删除
唯一约束,账户提供者和账户id的组合是唯一的


Session
expires 存DateTime

类型
DateTime
string

prisma 有实时数据库事件
orm,简单地与数据库对话
迁移系统

nextjs 构建全栈web应用程序的react框架

文件系统的路由器

文件系统的动态路由

按文件路径的API

router.push()

swr
swr 好处,数据与组件解耦。
请求有缓存
2秒内只发一个请求
可以设置轮询时间

zustand
替代redux的全局状态管理工具