Лучший способ изучить такой инструмент, как React, — создать
Наше приложение будет иметь следующие функции:
аутентификация с использованием NextAuth и Twitter OAuth
возможность добавить новый твит
возможность просмотра списка твитов
возможность просмотра профиля пользователя только с его твитами
Код приложения, которое мы будем создавать, доступен на GitHub. Мы будем использовать TypeScript для создания нашего приложения.
Предварительные
Next.js — один из самых популярных фреймворков React.js. Он имеет множество функций, таких как рендеринг на стороне сервера, поддержка TypeScript, оптимизация изображений, поддержка I18n, маршрутизация файловой системы и многое другое.
Prisma — это ORM для Node.js и TypeScript. Он также предоставляет множество функций, таких как необработанный доступ к базе данных, бесшовный API отношений, собственные типы баз данных и так далее.
Требуется программное обеспечение
Для запуска нашего приложения нам потребуется следующее:
Докер
над уровнем моря
пряжа
идти
В приложении будут использоваться следующие технологии:
Next.js: для создания нашего приложения
Prisma: для извлечения и сохранения данных в базу данных.
Chakra UI: для добавления стилей в наше приложение
NextAuth: для обработки аутентификации
React Query: для получения и обновления данных в нашем приложении.
Создание нового приложения Next.js
Теперь давайте начнем! Сначала мы создадим новое приложение Next.js, выполнив следующую команду из нашего терминала:
yarn create
Нам нужно будет ввести имя приложения, когда команда запросит его. Мы можем назвать это как угодно. Однако в данном случае я назову его
$ yarn create
yarn create v1.22.5
[¼] ? Resolving packages...
[½] ? Fetching packages...
[¾] ? Linking dependencies...
[4/4] ? Building fresh packages...
success Installed «
—
✔ What is your project named?
Creating a new Next.js app in /
...
Initialized a git repository.
Success! Created
Inside that directory, you can run several commands:
yarn dev
Starts the development server.
yarn build
Builds the app for production.
yarn start
Runs the built app in production mode.
We suggest that you begin by typing:
cd
yarn dev
Теперь мы можем зайти в каталог
cd
Наше приложение Next.js должно быть запущено на http: //localhost:3000. Мы должны увидеть следующий экран:
Приложение Next.js, работающее на локальном хосте: 3000
Добавление базы данных Dockerized PostgreSQL
Затем давайте добавим базу данных Dockerized PostgreSQL, чтобы мы могли сохранять в ней пользователей и твиты. Мы можем создать новый
version: «3»
services:
db:
container_name: db
image: postgres:11.
ports:
— «5432:5432»
volumes:
— db_data: /var/lib/postgresql/data
restart:
volumes:
db_data:
Если Docker запущен на нашем компьютере, мы можем выполнить следующую команду из корня нашего приложения, чтобы запустить наш контейнер PostgreSQL:
Приведенная выше команда запустит контейнер PostgreSQL, и к нему можно будет получить доступ на postgresql: //postgres: @localhost:5432/postgres. Обратите внимание, что вы также можете использовать локальную установку Postgres вместо Dockerized.
Добавление пользовательского интерфейса чакры
Chakra UI — это очень простая библиотека компонентов React.js. Он очень популярен и имеет такие функции, как доступность, поддержка как светлого, так и темного режима и многое другое. Мы будем использовать Chakra UI для стилизации нашего пользовательского интерфейса. Мы можем установить этот пакет, выполнив следующую команду из корня нашего приложения:
yarn add @
Давайте переименуем наш _app.jsфайл _app.tsxв pagesкаталог и заменим его содержимое следующим:
// pages/_app.tsx
import { ChakraProvider } from «@
import { AppProps } from «next/app»;
import Head from «next/head»;
import React from «react»;
const App = ({ Component, pageProps }: AppProps) => {
return (
<>
</>
) ;
};
export default App;
Поскольку мы добавили новый файл TypeScript, нам нужно перезапустить наш сервер Next.js. Как только мы перезапустим наш сервер, мы получим следующую ошибку:
$ yarn dev
yarn run v1.22.5
$ next dev
ready — started server on http: //localhost:3000
It looks like you’re trying to use TypeScript but do not have the required package (s) installed.
Please install typescript, @types/react, and @types/node by running:
yarn add —dev typescript @types/react @types/node
If you are not trying to use TypeScript, please remove the tsconfig.json file from your package root (and any TypeScript files in your pages directory).
Это связано с тем, что мы добавили новый файл TypeScript, но не добавили необходимые зависимости, необходимые для их запуска. Мы можем исправить это, установив недостающие зависимости. Из корня нашего приложения мы можем выполнить следующую команду, чтобы установить недостающие зависимости:
yarn add —dev typescript @types/react @types/node
Теперь, если мы запустим наш сервер Next.js, наше приложение должно скомпилироваться:
$ yarn dev
yarn run v1.22.5
$ next dev
ready — started server on http: //localhost:3000
We detected TypeScript in your project and created a tsconfig.json file for you.
event — compiled successfully
Добавление NextAuth
NextAuth — это библиотека аутентификации для Next.js. Он простой и понятный, гибкий и безопасный по умолчанию. Чтобы настроить NextAuth в нашем приложении, нам нужно установить его, выполнив следующую команду из корня нашего приложения:
yarn add
Далее нам нужно будет обновить наш pages/_app.tsxфайл со следующим содержимым:
// pages/_app.tsx
import { ChakraProvider } from «@
import { Provider as NextAuthProvider } from «
import { AppProps } from «next/app»;
import Head from «next/head»;
import React from «react»;
const App = ({ Component, pageProps }: AppProps) => {
return (
<>
</>
) ;
};
export default App;
Здесь мы оборачиваем наше приложение файлом NextAuthProvider. Далее нам нужно создать новый файл с именем [...nextauth].tsвнутри pages/api/authкаталога со следующим содержимым:
// pages/api/auth/[...nextauth].ts
import { NextApiRequest, NextApiResponse } from «next»;
import NextAuth from «
import Providers from «
const options = {
providers: [
Providers.Twitter ({
clientId: process.env.TWITTER_KEY,
clientSecret: process.env.TWITTER_SECRET,
}),
],
};
export default NextAuth (options) ;
Приведенный выше файл будет отвечать за обработку нашей аутентификации с использованием маршрутов API Next.js. Затем мы создадим новый файл с именем.envв корне нашего приложения для хранения всех наших переменных среды со следующим содержимым:
DATABASE_URL="postgresql://postgres:@localhost:5432/postgres?synchronize=true"
NEXTAUTH_URL=http: //localhost:3000
NEXT_PUBLIC_API_URL=http: //localhost:3000
TWITTER_KEY=""
TWITTER_SECRET=""
Переменные среды Twitter будут генерироваться из Twitter API. Мы будем делать это дальше. Мы можем создать новое приложение Twitter из панели инструментов Twitter Developer.
Создайте новое приложение Twitter, введя его имя и нажав кнопку «Завершить «.
Создайте новое приложение Twitter
Скопируйте ключ API, секретный ключ API и токен носителя на следующем экране.
Учетные данные нашего приложения Twitter
Измените разрешения приложения с «Только чтение» на «Чтение и запись «на следующем экране.
Разрешения приложения Твиттера
Нажмите кнопку «Изменить «рядом с настройками аутентификации, чтобы включить
Настройки аутентификации для нашего приложения Twitter
Включите трехсторонний протокол OAuth и запросите адрес электронной почты у пользователей, а также добавьте http: //localhost:3000/api/auth/callback/twitter в качестве
Измените настройки аутентификации в нашем приложении Twitter.
Теперь наш трехсторонний OAuth должен быть включен.
Включите трехэтапный протокол OAuth для нашего приложения Twitter.
Вставьте значение ключа API из шага 2 в переменную среды TWITTER_KEY, а значение секретного ключа API — в переменную среды TWITTER_SECRET.
Теперь наш.envфайл должен выглядеть так:
DATABASE_URL="postgresql://postgres:@localhost:5432/postgres"
NEXTAUTH_URL=http: //localhost:3000
NEXT_PUBLIC_API_URL=http: //localhost:3000
TWITTER_KEY="1234" // Replace this with your own API key
TWITTER_SECRET="secret" // Replaces this with your own API secret key
Теперь, если мы перезапустим наш сервер Next.js и посетим http: //localhost:3000/api/auth/signin, мы сможем увидеть кнопку «Войти через Twitter «:
Войти с помощью кнопки Twitter
Если мы нажмем на эту кнопку, мы сможем авторизовать наше приложение Twitter, но не сможем войти в наше приложение. Наш терминал покажет следующую ошибку:
[
https://next-auth.js.org/warnings#jwt_auto_generated_signing_key
Мы исправим эту проблему позже, когда будем добавлять и настраивать Prisma.
Добавление и настройка Prisma
yarn add prisma @prisma/client
Затем давайте создадим новый файл с именем prisma.tsвнутри lib/clientsкаталога со следующим содержимым:
// lib/clients/prisma.ts
import { PrismaClient } from «@prisma/client»;
const prisma = new PrismaClient () ;
export default prisma;
Это PrismaClientбудет повторно использоваться в нескольких файлах. Далее нам нужно будет обновить наш pages/api/auth/[...nextauth].tsфайл со следующим содержимым:
...
import prisma from «.../... /... /lib/clients/prisma»;
import Adapters from «
...
const options = {
providers: [
...
],
adapter: Adapters.Prisma.Adapter ({ prisma }),
};
...
Теперь, если мы посетим http: //localhost:3000/api/auth/signin, мы получим следующую ошибку на нашем терминале:
Error: @prisma/client did not initialize yet. Please run «prisma generate» and try to import it again.
Чтобы решить эту проблему, нам нужно сделать следующее:
Запускаем npx prisma initиз корня нашего приложения:
$ npx prisma init
Environment variables loaded from.env
✔ Your Prisma schema was created at prisma/schema.prisma.
You can now open it in your favorite editor.
warn Prisma would have added DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public" but it already exists in.env
Next steps:
1. Set the DATABASE_URL in the.env file to point to your existing database. If your database has no tables yet, read https://pris.ly/d/getting-started.
2. Set the provider of the datasource block in schema.prisma to match your database: postgresql, mysql or sqlite.
3. Run prisma introspect to turn your database schema into a Prisma data model.
4. Run prisma generate to install Prisma Client. You can then start querying your database.
More information in our documentation:
https://pris.ly/d/getting-started
Запускаем npx prisma generateиз корня нашего приложения:
$ npx prisma generate
4s
Environment variables loaded from.env
Prisma schema loaded from prisma/schema.prisma
Error:
You don’t have any models defined in your schema.prisma, so nothing will be generated.
You can define a model like this:
model User {
id Int @id @default (autoincrement ())
email String @unique
name String?
}
More information in our documentation:
https://pris.ly/d/prisma-schema
Обновите prisma/schema.prismaфайл схемой, которую ожидает NextAuth:
// prisma/schema.prisma
generator client {
provider = «
}
datasource db {
provider = «postgresql»
url = env («DATABASE_URL»)
}
model Account {
id Int @id @default (autoincrement ())
compoundId String @unique @map («compound_id»)
userId Int @map («user_id»)
providerType String @map («provider_type»)
providerId String @map («provider_id»)
providerAccountId String @map («provider_account_id»)
refreshToken String? @map («refresh_token»)
accessToken String? @map («access_token»)
accessTokenExpires DateTime? @map («access_token_expires»)
createdAt DateTime @default (now ()) @map («created_at»)
updatedAt DateTime @default (now ()) @map («updated_at»)
@@index ([providerAccountId], name: «providerAccountId»)
@@index ([providerId], name: «providerId»)
@@index ([userId], name: «userId»)
@@map («accounts»)
}
model Session {
id Int @id @default (autoincrement ())
userId Int @map («user_id»)
expires DateTime
sessionToken String @unique @map («session_token»)
accessToken String @unique @map («access_token»)
createdAt DateTime @default (now ()) @map («created_at»)
updatedAt DateTime @default (now ()) @map («updated_at»)
@@map («sessions»)
}
model User {
id Int @id @default (autoincrement ())
name String?
email String? @unique
emailVerified DateTime? @map («email_verified»)
image String?
createdAt DateTime @default (now ()) @map («created_at»)
updatedAt DateTime @default (now ()) @map («updated_at»)
tweets Tweet[]
@@map («users»)
}
model VerificationRequest {
id Int @id @default (autoincrement ())
identifier String
token String @unique
expires DateTime
createdAt DateTime @default (now ()) @map («created_at»)
updatedAt DateTime @default (now ()) @map («updated_at»)
@@map («verification_requests»)
}
Добавьте схему для Tweet в prisma/schema.prismaфайл:
// prisma/schema.prisma
...
model Tweet {
id Int @id @default (autoincrement ())
body String
userId Int
createdAt DateTime @default (now ()) @map («created_at»)
updatedAt DateTime @default (now ()) @map («updated_at»)
author User @relation (fields: [userId], references: [id])
@@map («tweets»)
}
Запустите npx prisma migrate dev —
Теперь, если мы посетим http: //localhost:3000/api/auth/signin и нажмем кнопку Sign in with Twitter, мы войдем в наше приложение с помощью Twitter.
Добавление некоторых исходных данных
Чтобы пользовательский интерфейс не был полностью голым, пока мы работаем над приложением, давайте добавим некоторые начальные данные.
Начнем с установки пары зависимостей:
yarn add -D faker
Это задействует faker.js, который поможет нам генерировать поддельные данные, а также его зависимость от
Затем создайте новый seed.tsфайл в prismaпапке и добавьте следующее содержимое:
import faker from «faker»;
import prisma from «.../lib/clients/prisma»;
async function main () {
const listOfNewUsers = [...new Array (5) ].map (() => {
return {
email: faker.internet.email (),
name: faker.name.findName (),
image: faker.image.image (),
tweets: {
create: {
body: faker.lorem.sentence (),
},
},
};
}) ;
for (let data of listOfNewUsers) {
const user = await prisma.user.create ({
data,
}) ;
console.log (user) ;
}
}
main ()
.catch ((e) => {
console.error (e) ;
process.exit (1) ;
})
.finally (async () => {
await prisma. $disconnect () ;
}) ;
Нам также потребуется обновить наш tsconfig.jsonфайл, как показано ниже:
{
«compilerOptions»: {
«target»: «es5»,
«lib»: [
«dom»,
«dom.iterable»,
«esnext»
],
«allowJs»: true,
«skipLibCheck»: true,
«strict»: false,
«forceConsistentCasingInFileNames»: true,
«noEmit»: true,
«esModuleInterop»: true,
«module»: «commonjs»,
«moduleResolution»: «node»,
«resolveJsonModule»: true,
«isolatedModules»: true,
«jsx»: «preserve»,
«baseUrl»: «.»,
«paths»: {
«*»: [
«/*»
],
«components/*»: [
«components/*»
],
«pages/*»: [
«pages/*»
],
«types/*»: [
«types/*»
],
«lib/*»: [
«lib/*»
],
},
},
«include»: [
«
«**/*.ts»,
«**/*.tsx»
],
«exclude»: [
«node_modules»
]
}
Наконец, мы можем запустить npx prisma db seed —
Добавление реагирующего запроса
React Query — очень популярный и эффективный способ получения данных в приложениях React.js. Давайте добавим React Query в наше приложение. Мы можем установить React Query, выполнив следующую команду из корня нашего приложения:
yarn add
Затем давайте создадим новый файл с именем
// lib/clients/
import { QueryClient } from «
const queryClient = new QueryClient () ;
export default queryClient;
Нам также нужно обновить наш pages/_app.tsxфайл со следующим содержимым:
// pages/_app.tsx
...
import { QueryClientProvider } from «
import { Hydrate } from «
import queryClient from «.../lib/clients/
const App = ({ Component, pageProps }: AppProps) => {
return (
) ;
};
export default App;
Здесь мы оборачиваем наше приложение с помощью QueryClientProvider, который предоставит QueryClientнашему приложению a.
Возможность просмотра списка твитов
Давайте создадим новый файл
// lib/queries/
const fetchTweets = async () => {
const res = await fetch (`${process.env.NEXT_PUBLIC_API_URL}/api/tweets`) ;
const data = await res.json () ;
return data;
};
export default fetchTweets;
Эта функция будет отвечать за получение всех твитов в нашем приложении. Затем создайте новый файл tweets.tsxвнутри pagesкаталога со следующим содержимым:
// pages/tweets.tsx
import fetchTweets from «.../lib/queries/
import queryClient from «.../lib/clients/
import { GetServerSideProps, InferGetServerSidePropsType } from «next»;
import { useSession } from «
import Head from «next/head»;
import React from «react»;
import { useQuery } from «
import { dehydrate } from «
const TweetsPage: InferGetServerSidePropsType<
typeof getServerSideProps
> = ({}) => {
const { data } = useQuery («tweets», fetchTweets) ;
const [session] = useSession () ;
if (! session) {
return
;
}
return (
<>
{console.log (JSON.stringify (data, null, 2))}
</>
) ;
};
export const getServerSideProps: GetServerSideProps = async ({ req }) => {
await queryClient.prefetchQuery («tweets», fetchTweets) ;
return {
props: {
dehydratedState: dehydrate (queryClient),
},
};
};
export default TweetsPage;
getServerSideProps — это функция Next.js, которая помогает получать данные с сервера. Давайте также создадим новый файл с именем index.tsвнутри pages/api/tweetsкаталога со следующим содержимым:
// pages/api/tweets/index.ts
import prisma from «.../... /... /lib/clients/prisma»;
import type { NextApiRequest, NextApiResponse } from «next»;
export default async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method === «POST») {
try {
const { body } = req;
const tweet = await prisma.tweet.create ({ data: JSON.parse (body) }) ;
return res.status (200).json (tweet) ;
} catch (error) {
return res.status (422).json (error) ;
}
} else if (req.method === «GET») {
try {
const tweets = await prisma.tweet.findMany ({
include: {
author: true,
},
orderBy: [
{
createdAt: «desc»,
},
],
}) ;
return res.status (200).json (tweets) ;
} catch (error) {
return res.status (422).json (error) ;
}
}
res.end () ;
};
Здесь мы проверяем запрос. Если это POSTзапрос, мы создаем новый твит. Если это GETзапрос, мы отправляем все твиты с данными автора. Теперь, если мы посетим http: //localhost:3000/tweets, мы увидим все твиты в консоли нашего браузера.
Список твитов из конечной точки API
Обратите внимание, что, поскольку faker.js генерирует случайные данные, то, что вы видите в консоли браузера, будет отличаться от скриншота. Мы добавим возможность добавить твит позже.
Далее давайте создадим пользовательский интерфейс для отображения списка твитов. Мы можем создать новый файл с именем index.tsxвнутри components/pages/tweetsкаталога со следующим содержимым:
// components/pages/tweets/index.tsx
import { Box, Grid, Stack } from «@
import Tweet from «. /tweet»;
import React from «react»;
import ITweet from «types/tweet»;
const TweetsPageComponent = ({ tweets }) => {
return (
{tweets?.map ((tweet: ITweet) => {
return (
) ;
}) }
) ;
};
export default TweetsPageComponent;
Давайте также создадим новый файл с именем tweet.tsxв том же каталоге (components/pages/tweets) со следующим содержимым:
// components/pages/tweets/tweet.tsx
import { Avatar, Box, Stack, Text } from «@
import React, { FC } from «react»;
const Tweet: FC = ({ tweet }) => {
const authorNode = () => {
return (
<Stack
spacing={4}
isInline
alignItems="center"
p={4}
borderBottomWidth={1}
>
) ;
};
const bodyNode = () => {
return (
{tweet.body}
) ;
};
return (
{authorNode () }
{bodyNode () }
) ;
};
export default Tweet;
Далее давайте обновим наш pages/tweets.tsxфайл следующим содержимым:
// pages/tweets.tsx
...
import Page from «.../components/pages/tweets»;
...
const TweetsPage: InferGetServerSidePropsType<
typeof getServerSideProps
> = ({}) => {
...
return (
<>
</>
) ;
...
}
...
Здесь мы изменили интерфейс нашего приложения. Теперь, если мы посетим http: //localhost:3000/tweets, мы сможем увидеть следующее:
Список твитов
Возможность добавить новый твит
Давайте добавим текстовую область, через которую мы можем добавить новый твит. Для этого давайте создадим новый файл с именем
// components/pages/tweets/
import {
Box,
Button,
FormControl,
FormLabel,
Stack,
Textarea,
} from «@
import saveTweet from «.../... /... /lib/mutations/
import fetchTweets from «.../... /... /lib/queries/
import queryClient from «.../... /... /lib/clients/
import { useSession } from «
import React, { ChangeEvent, useState } from «react»;
import { useMutation, useQuery } from «
const AddNewTweetForm = () => {
const [body, setBody] = useState («») ;
const [session] = useSession () ;
const { refetch } = useQuery («tweets», fetchTweets) ;
const mutation = useMutation (saveTweet, {
onSuccess: async () => {
await queryClient.invalidateQueries («tweets») ;
refetch () ;
},
}) ;
if (! session) {
return
;
}
const handleSubmit = () => {
const data = {
body,
author: {
connect: { email: session.user.email },
},
};
mutation.mutate (data) ;
if (! mutation.error) {
setBody («») ;
}
};
return (
<Textarea
id="body"
value={body}
onChange={ (e: ChangeEvent
setBody (e.currentTarget.value)
}
/>
<Button
loadingText="Posting..."
onClick={handleSubmit}
isDisabled={! body.trim () }
>
Post
) ;
};
export default AddNewTweetForm;
Функция мутации отвечает за выполнение POSTзапроса к серверу. Он также повторно извлекает данные после успешного выполнения запроса. Кроме того, давайте создадим новый файл с именем
// lib/mutations/
const saveTweet = async (body: any) => {
const res = await fetch (`${process.env.NEXT_PUBLIC_API_URL}/api/tweets`, {
method: «POST»,
body: JSON.stringify (body),
}) ;
const data = await res.json () ;
return data;
};
export default saveTweet;
Нам также нужно изменить наш components/pages/tweets/index.tsxфайл со следующим содержимым:
// components/pages/tweets/index.tsx
...
import AddNewTweetForm from «. /
...
const TweetsPageComponent = ({ tweets }) => {
return (
...
) ;
};
export default TweetsPageComponent;
Теперь мы должны иметь возможность просматривать текстовое поле, если мы посетим http: //localhost:3000/tweets:
Textarea для добавления новых твитов
Мы также должны иметь возможность добавить новый твит, используя текстовое поле (это не будет твитом в вашей реальной учетной записи!):
Добавить новый твит
Далее мы добавим возможность просмотра профиля пользователя, который показывает только твиты, опубликованные этим пользователем.
Возможность просмотра профиля пользователя только с его твитами
Сначала мы создадим страницу, на которой будет отображаться список всех пользователей. Для этого нам нужно создать новый файл с именем index.tsxвнутри pages/usersкаталога со следующим содержимым:
// pages/users/index.tsx
import { GetServerSideProps, InferGetServerSidePropsType } from «next»;
import { useSession } from «
import Head from «next/head»;
import React from «react»;
import { useQuery } from «
import { dehydrate } from «
import Page from «.../... /components/pages/users»;
import queryClient from «.../... /lib/clients/
import fetchUsers from «.../... /lib/queries/
const MyAccountPage: InferGetServerSidePropsType<
typeof getServerSideProps
> = ({}) => {
const { data } = useQuery («users», fetchUsers) ;
const [session] = useSession () ;
if (! session) {
return
;
}
return (
<>
</>
) ;
};
export const getServerSideProps: GetServerSideProps = async ({ req }) => {
await queryClient.prefetchQuery («users», fetchUsers) ;
return {
props: {
dehydratedState: dehydrate (queryClient),
},
};
};
export default MyAccountPage;
Нам также нужно создать новый файл с именем
// lib/queries/
const fetchUsers = async () => {
const res = await fetch (`${process.env.NEXT_PUBLIC_API_URL}/api/users`) ;
const data = await res.json () ;
return data;
};
export default fetchUsers;
Эта функция будет отвечать за получение всех пользователей из конечной точки API. Нам также нужно создать новый файл с именем index.tsxвнутри components/pages/usersкаталога со следующим содержимым:
// components/pages/users/index.tsx
import { Box, Grid, Stack } from «@
import React from «react»;
import User from «. /user»;
const UsersPageComponent = ({ users }) => {
return (
{users?.map ((user) => {
return (
) ;
}) }
) ;
};
export default UsersPageComponent;
Далее давайте создадим файл с именем user.tsxвнутри того же каталога (components/pages/users) со следующим содержимым:
// components/pages/users/user.tsx
import { Avatar, Box, Stack, Text, Button } from «@
import Link from «next/link»;
import React, { FC } from «react»;
const User: FC = ({ user }) => {
const authorNode = () => {
return (
<Stack
spacing={4}
isInline
alignItems="center"
p={4}
borderBottomWidth={1}
>
) ;
};
const bodyNode = () => {
return (
{user.email}
) ;
};
const buttonNode = () => {
return (
<Link href={`/users/${user.id}`}>
) ;
};
return (
{authorNode () }
{bodyNode () }
{buttonNode () }
) ;
};
export default User;
И еще один файл с именем index.tsвнутри pages/api/usersкаталога со следующим содержимым:
// pages/api/users/index.ts
import prisma from «.../... /... /lib/clients/prisma»;
import type { NextApiRequest, NextApiResponse } from «next»;
export default async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method === «GET») {
try {
const users = await prisma.user.findMany ({
orderBy: [
{
createdAt: «desc»,
},
],
}) ;
return res.status (200).json (users) ;
} catch (error) {
return res.status (422).json (error) ;
}
}
res.end () ;
};
Вышеупомянутая функция отвечает за отправку сведений обо всех пользователях. Теперь, если мы посетим http: //localhost:3000/users, мы сможем увидеть список пользователей:
Список пользователей
Теперь давайте создадим страницу для отображения сведений об одном пользователе. Для этого нам нужно создать новый файл с именем [id].tsxвнутри pages/usersкаталога со следующим содержимым:
// pages/users/[id].tsx
import Page from «.../... /components/pages/users/[id]»;
import queryClient from «.../... /lib/clients/
import fetchUser from «.../... /lib/queries/
import { GetServerSideProps, InferGetServerSidePropsType } from «next»;
import { getSession, useSession } from «
import Head from «next/head»;
import React from «react»;
import { useQuery } from «
import { dehydrate } from «
const MyAccountPage: InferGetServerSidePropsType
id,
}) => {
const { data } = useQuery («user», () => fetchUser (parseInt (id as string)));
const [session] = useSession () ;
if (! session) {
return
;
}
return (
<>
</>
) ;
};
export const getServerSideProps: GetServerSideProps = async ({ query }) => {
await queryClient.prefetchQuery («user», () =>
fetchUser (parseInt (query.id as string))
) ;
return {
props: {
dehydratedState: dehydrate (queryClient),
id: query.id,
},
};
};
export default MyAccountPage;
Значение query.idопределяет idтекущий пользователь. Нам также нужно создать новый файл с именем
// lib/queries/
const fetchUser = async (userId: number) => {
const res = await fetch (
`${process.env.NEXT_PUBLIC_API_URL}/api/users/${userId}`
) ;
const data = await res.json () ;
return data;
};
export default fetchUser;
Вышеупомянутая функция будет отвечать за выполнение GETзапроса к конечной точке API. Далее нам нужно создать новый файл с именем index.tsxвнутри components/pages/users/[id]каталога со следующим содержимым:
// components/pages/users/[id]/index.tsx
import { Avatar, Box, Grid, Stack, Text } from «@
import Tweet from «. /tweet»;
import React, { FC } from «react»;
const UsersPageComponent: FC = ({ user }) => {
const authorNode = () => {
return (
{user?.name}
) ;
};
return (
{authorNode () }
{user?.tweets.map ((tweet) => {
return (
) ;
}) }
) ;
};
export default UsersPageComponent;
Далее нам нужно создать еще один файл с именем tweet.tsxв том же каталоге (components/pages/users/[id]) со следующим содержимым:
// components/pages/users/[id]/tweet.tsx
import { Box, Stack, Text } from «@
import React, { FC } from «react»;
const Tweet: FC = ({ tweet }) => {
const bodyNode = () => {
return (
{tweet.body}
) ;
};
return (
) ;
};
export default Tweet;
Наконец, нам нужно создать еще один файл с именем [id].tsвнутри pages/api/usersкаталога со следующим содержимым:
// pages/api/users/[id].ts
import prisma from «.../... /... /lib/clients/prisma»;
import type { NextApiRequest, NextApiResponse } from «next»;
export default async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method === «GET») {
const userId = parseInt (req.query.id as string) ;
try {
const tweets = await prisma.user.findUnique ({
include: {
tweets: true,
},
where: {
id: userId,
},
}) ;
return res.status (200).json (tweets) ;
} catch (error) {
console.log (error) ;
return res.status (422).json (error) ;
}
}
res.end () ;
};
Вышеупомянутая функция будет отвечать за отправку сведений о пользователе, idкоторый совпадает с req.query.id. Мы конвертируем его в число, так как Prisma требует, чтобы оно было числовым. Теперь, если мы посетим http: //localhost:3000/users и нажмем кнопку View profile для пользователя, мы сможем увидеть список твитов, опубликованных этим пользователем.
Профиль пользователя со всеми твитами, опубликованными этим пользователем
Вывод
В этом руководстве мы узнали, как мы можем использовать Next.js и Prisma вместе для создания клона Twitter. Очевидно, что Twitter состоит из множества других функций, таких как ретвиты, комментарии и функции обмена для каждого твита. Тем не менее, это руководство должно предоставить основу для создания таких функций.