forked from templates/nextjs-template
style: Обновлены правила код стайла
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Источники данных
|
||||
description: Какие источники данных используются в проекте и как с ними работать.
|
||||
keywords: [данные, api, rest, realtime, клиент, swr, infrastructure, введение, карта раздела]
|
||||
keywords: [данные, api, rest, realtime, клиент, swr, infra, введение, карта раздела]
|
||||
---
|
||||
|
||||
# Источники данных
|
||||
@@ -10,7 +10,7 @@ keywords: [данные, api, rest, realtime, клиент, swr, infrastructure,
|
||||
|
||||
## Принципы раздела
|
||||
|
||||
- **Клиент — в `infrastructure/`.** Каждый внешний сервис — отдельный модуль слоя `infrastructure/{service-name}/`.
|
||||
- **Клиент — в `infra/`.** Каждый внешний сервис — отдельный модуль слоя `infra/{service-name}/`.
|
||||
- **Прямой `fetch` запрещён.** Запросы идут только через клиент модуля. Исключения — точечные и обоснованные.
|
||||
- **Источник данных диктует канал.** REST, realtime и т.п. — независимые подразделы, у каждого своя модель клиента и своё потребление.
|
||||
- **Серверные и клиентские компоненты потребляют по-разному.** Server Components — прямой `await` метода клиента, клиентские — через готовые GET-хуки REST-клиента (`useGetUserList`, `useGetPostDetail` и т.п.). SWR инкапсулирован в хуке, компонент про него не знает.
|
||||
@@ -40,7 +40,7 @@ keywords: [данные, api, rest, realtime, клиент, swr, infrastructure,
|
||||
|
||||
Канал push-данных: WebSocket, SSE, событийные шины. Транспорт не зашит в правила — важна абстракция «подписка».
|
||||
|
||||
- [Realtime](./realtime.md) — клиент realtime в `infrastructure/`, потребление через `useSWRSubscription` или прямые подписки.
|
||||
- [Realtime](./realtime.md) — клиент realtime в `infra/`, потребление через `useSWRSubscription` или прямые подписки.
|
||||
|
||||
## Что даёт раздел
|
||||
|
||||
@@ -48,7 +48,7 @@ keywords: [данные, api, rest, realtime, клиент, swr, infrastructure,
|
||||
|
||||
- Где живёт код работы с API и почему именно там.
|
||||
- Когда генерировать клиент автоматически, а когда писать вручную, и как структурирован каждый из вариантов.
|
||||
- Какие GET-хуки относятся к REST-клиенту и почему они живут в `infrastructure/{service-name}/hooks/`.
|
||||
- Какие GET-хуки относятся к REST-клиенту и почему они живут в `infra/{service-name}/hooks/`.
|
||||
- Как выбрать стратегию получения REST-данных под конкретную ситуацию.
|
||||
- Как подключать realtime-источники в общую модель работы с данными.
|
||||
- Какие правила обязательны и какие отклонения допустимы.
|
||||
|
||||
@@ -10,7 +10,7 @@ keywords: [realtime, websocket, sse, подписка, swr subscription, useSWRS
|
||||
|
||||
## Принципы
|
||||
|
||||
- **Клиент realtime — в `infrastructure/`** отдельным модулем по имени канала. То же правило, что и для REST: никаких прямых соединений в коде приложения.
|
||||
- **Клиент realtime — в `infra/`** отдельным модулем по имени канала. То же правило, что и для REST: никаких прямых соединений в коде приложения.
|
||||
- **Подписка — единица потребления.** Клиент даёт функцию `subscribe(topic, handler) → unsubscribe`. Внутри — конкретный транспорт.
|
||||
- **Использование на клиенте — два сценария:**
|
||||
- **`useSWRSubscription`** — для данных, которые показываются в UI и должны кешироваться/синхронизироваться с REST.
|
||||
@@ -19,7 +19,7 @@ keywords: [realtime, websocket, sse, подписка, swr subscription, useSWRS
|
||||
## Размещение клиента
|
||||
|
||||
```text
|
||||
src/infrastructure/
|
||||
src/infra/
|
||||
└── {channel-name}/
|
||||
├── connection.ts # установление соединения, реконнект
|
||||
├── subscribe.ts # subscribe(topic, handler) → unsubscribe
|
||||
@@ -33,7 +33,7 @@ src/infrastructure/
|
||||
'use client'
|
||||
|
||||
import useSWRSubscription from 'swr/subscription'
|
||||
import { subscribe } from 'infrastructure/notifications'
|
||||
import { subscribe } from 'infra/notifications'
|
||||
|
||||
export function NotificationCounter() {
|
||||
const { data: count } = useSWRSubscription(
|
||||
@@ -56,7 +56,7 @@ export function NotificationCounter() {
|
||||
'use client'
|
||||
|
||||
import { useEffect } from 'react'
|
||||
import { subscribe } from 'infrastructure/notifications'
|
||||
import { subscribe } from 'infra/notifications'
|
||||
import { showToast } from 'ui/toast'
|
||||
|
||||
export function NotificationsToaster() {
|
||||
@@ -74,6 +74,6 @@ export function NotificationsToaster() {
|
||||
|
||||
## Запрет прямых соединений
|
||||
|
||||
Создавать `new WebSocket(...)`, `new EventSource(...)` или подписываться на событийные шины напрямую в коде приложения — запрещено. Все соединения проходят через клиент в `infrastructure/`.
|
||||
Создавать `new WebSocket(...)`, `new EventSource(...)` или подписываться на событийные шины напрямую в коде приложения — запрещено. Все соединения проходят через клиент в `infra/`.
|
||||
|
||||
Исключения — точечные и обоснованные (например, диагностический скрипт), помечаются комментарием.
|
||||
|
||||
@@ -19,7 +19,7 @@ https://petstore3.swagger.io/api/v3/openapi.json
|
||||
Имена модуля:
|
||||
|
||||
```text
|
||||
src/infrastructure/pet-store-api/
|
||||
src/infra/pet-store-api/
|
||||
petStoreApi
|
||||
pet-store-api.generated.ts
|
||||
```
|
||||
@@ -31,7 +31,7 @@ pet-store-api.generated.ts
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"codegen:pet-store-api": "npx @gromlab/api-codegen@latest -i https://petstore3.swagger.io/api/v3/openapi.json -o src/infrastructure/pet-store-api/generated -n pet-store-api.generated"
|
||||
"codegen:pet-store-api": "npx @gromlab/api-codegen@latest -i https://petstore3.swagger.io/api/v3/openapi.json -o src/infra/pet-store-api/generated -n pet-store-api.generated"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -53,7 +53,7 @@ npm run codegen:pet-store-api
|
||||
Ожидаемый результат:
|
||||
|
||||
```text
|
||||
src/infrastructure/pet-store-api/generated/
|
||||
src/infra/pet-store-api/generated/
|
||||
└── pet-store-api.generated.ts
|
||||
```
|
||||
|
||||
@@ -77,7 +77,7 @@ petStoreApi.pet.getPetById(...)
|
||||
Сгенерированный код не должен напрямую использоваться из приложения. Сначала создаётся настроенный инстанс клиента.
|
||||
|
||||
```ts
|
||||
// src/infrastructure/pet-store-api/client.ts
|
||||
// src/infra/pet-store-api/client.ts
|
||||
import { Api, HttpClient } from './generated/pet-store-api.generated'
|
||||
|
||||
const httpClient = new HttpClient({
|
||||
@@ -102,7 +102,7 @@ export const petStoreApi = new Api(httpClient)
|
||||
Сгенерированный файл не правится руками. Если OpenAPI-спецификация неполная или генератор дал слишком общий тип (`object`, `unknown`, отсутствующее поле), расширения живут в `types/`.
|
||||
|
||||
```text
|
||||
src/infrastructure/biocad-less-api/
|
||||
src/infra/biocad-less-api/
|
||||
├── generated/
|
||||
│ └── biocad-less-api.generated.ts
|
||||
├── types/
|
||||
@@ -115,7 +115,7 @@ src/infrastructure/biocad-less-api/
|
||||
Пример расширения generated-типа:
|
||||
|
||||
```ts
|
||||
// src/infrastructure/biocad-less-api/types/term.ts
|
||||
// src/infra/biocad-less-api/types/term.ts
|
||||
import type { TermRecordItem } from '../generated/biocad-less-api.generated'
|
||||
|
||||
declare module '../generated/biocad-less-api.generated' {
|
||||
@@ -149,7 +149,7 @@ export type TermRecordItemExtended = Omit<
|
||||
```
|
||||
|
||||
```ts
|
||||
// src/infrastructure/biocad-less-api/types/index.ts
|
||||
// src/infra/biocad-less-api/types/index.ts
|
||||
export type { TermRecordItemExtended } from './term'
|
||||
```
|
||||
|
||||
@@ -158,18 +158,18 @@ export type { TermRecordItemExtended } from './term'
|
||||
## Публичный API
|
||||
|
||||
```ts
|
||||
// src/infrastructure/pet-store-api/index.ts
|
||||
// src/infra/pet-store-api/index.ts
|
||||
export { petStoreApi } from './client'
|
||||
export type { Pet } from './generated/pet-store-api.generated'
|
||||
export * from './hooks'
|
||||
```
|
||||
|
||||
Наружу импортируют только из `infrastructure/pet-store-api`, не из `generated/`.
|
||||
Наружу импортируют только из `infra/pet-store-api`, не из `generated/`.
|
||||
|
||||
Если у модуля есть расширенные типы, они тоже реэкспортируются через `index.ts`:
|
||||
|
||||
```ts
|
||||
// src/infrastructure/biocad-less-api/index.ts
|
||||
// src/infra/biocad-less-api/index.ts
|
||||
export type { TermRecordItemExtended } from './types'
|
||||
```
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: GET-хуки REST-клиента
|
||||
description: Прозрачные SWR-обёртки над GET-методами REST-клиента.
|
||||
keywords: [rest, swr, get-хуки, client components, infrastructure]
|
||||
keywords: [rest, swr, get-хуки, client components, infra]
|
||||
---
|
||||
|
||||
# GET-хуки REST-клиента
|
||||
@@ -13,7 +13,7 @@ GET-хуки REST-клиента — прозрачные SWR-обёртки н
|
||||
GET-хуки принадлежат REST-клиенту конкретного сервиса и живут рядом с ним:
|
||||
|
||||
```text
|
||||
src/infrastructure/
|
||||
src/infra/
|
||||
└── pet-store-api/
|
||||
├── client.ts
|
||||
├── generated/
|
||||
@@ -41,7 +41,7 @@ src/infrastructure/
|
||||
## Пример списка
|
||||
|
||||
```ts
|
||||
// src/infrastructure/pet-store-api/hooks/use-get-pet-list.hook.ts
|
||||
// src/infra/pet-store-api/hooks/use-get-pet-list.hook.ts
|
||||
import useSWR from 'swr'
|
||||
import type { SWRConfiguration } from 'swr'
|
||||
import { petStoreApi } from '../client'
|
||||
@@ -74,7 +74,7 @@ import { SWRConfig, unstable_serialize } from 'swr'
|
||||
import {
|
||||
getPetListKey,
|
||||
petStoreApi,
|
||||
} from 'infrastructure/pet-store-api'
|
||||
} from 'infra/pet-store-api'
|
||||
|
||||
export default function PetsLayout({ children }: { children: ReactNode }) {
|
||||
const petsPromise = petStoreApi.pet.findPetsByStatus({ status: 'available' })
|
||||
@@ -102,7 +102,7 @@ const { data: pets } = useGetPetList('available')
|
||||
## Пример detail-запроса
|
||||
|
||||
```ts
|
||||
// src/infrastructure/pet-store-api/hooks/use-get-pet-detail.hook.ts
|
||||
// src/infra/pet-store-api/hooks/use-get-pet-detail.hook.ts
|
||||
import useSWR from 'swr'
|
||||
import type { SWRConfiguration } from 'swr'
|
||||
import { petStoreApi } from '../client'
|
||||
@@ -141,23 +141,23 @@ const key = isReady ? getPetDetailKey(id) : null
|
||||
## Экспорт
|
||||
|
||||
```ts
|
||||
// src/infrastructure/pet-store-api/hooks/index.ts
|
||||
// src/infra/pet-store-api/hooks/index.ts
|
||||
export { getPetListKey, useGetPetList } from './use-get-pet-list.hook'
|
||||
export type { PetStatus } from './use-get-pet-list.hook'
|
||||
export { getPetDetailKey, useGetPetDetail } from './use-get-pet-detail.hook'
|
||||
```
|
||||
|
||||
```ts
|
||||
// src/infrastructure/pet-store-api/index.ts
|
||||
// src/infra/pet-store-api/index.ts
|
||||
export { petStoreApi } from './client'
|
||||
export type { Pet } from './generated/pet-store-api.generated'
|
||||
export * from './hooks'
|
||||
```
|
||||
|
||||
## Где заканчивается infrastructure
|
||||
## Где заканчивается infra
|
||||
|
||||
```ts
|
||||
// Хорошо: infrastructure, прозрачный GET-хук
|
||||
// Хорошо: infra, прозрачный GET-хук
|
||||
const { data: pets } = useGetPetList('available')
|
||||
```
|
||||
|
||||
@@ -184,7 +184,7 @@ const { data } = useSWR(
|
||||
() => petStoreApi.pet.findPetsByStatus({ status }),
|
||||
)
|
||||
|
||||
// Плохо — несколько GET внутри infrastructure-хука
|
||||
// Плохо — несколько GET внутри infra-хука
|
||||
export const usePetDashboard = () => {
|
||||
const available = useGetPetList('available')
|
||||
const sold = useGetPetList('sold')
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
title: Создание клиента
|
||||
description: Из чего состоит REST-клиент и какие части нужно подготовить перед использованием API.
|
||||
keywords: [rest, клиент, infrastructure, методы, openapi, get-хуки, swr]
|
||||
keywords: [rest, клиент, infra, методы, openapi, get-хуки, swr]
|
||||
---
|
||||
|
||||
# Создание клиента
|
||||
|
||||
REST-клиент — это infrastructure-модуль, через который проект работает с внешним REST API.
|
||||
REST-клиент — это infra-модуль, через который проект работает с внешним REST API.
|
||||
|
||||
На этом этапе нужно подготовить клиент сервиса: создать оболочку клиента, получить методы API и добавить GET-хуки для клиентских компонентов.
|
||||
|
||||
@@ -57,7 +57,7 @@ GET-хуки именуются с префиксом `useGet`: `useGetPetList`,
|
||||
## Структура модуля
|
||||
|
||||
```text
|
||||
src/infrastructure/{service-name}/
|
||||
src/infra/{service-name}/
|
||||
├── client.ts # самописная оболочка и инстанс клиента
|
||||
├── generated/ или methods/ # методы API
|
||||
├── hooks/ # GET-хуки REST-клиента
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Ручное создание
|
||||
description: Создание REST-клиента вручную, когда OpenAPI нет или он неполный.
|
||||
keywords: [rest, ручной клиент, fetch, methods, dto, errors, infrastructure]
|
||||
keywords: [rest, ручной клиент, fetch, methods, dto, errors, infra]
|
||||
---
|
||||
|
||||
# Ручное создание
|
||||
@@ -13,7 +13,7 @@ keywords: [rest, ручной клиент, fetch, methods, dto, errors, infrast
|
||||
## Что нужно создать
|
||||
|
||||
```text
|
||||
src/infrastructure/
|
||||
src/infra/
|
||||
└── pet-project-api/
|
||||
├── methods/
|
||||
│ └── posts.ts
|
||||
@@ -43,7 +43,7 @@ src/infrastructure/
|
||||
DTO запросов и ответов живут в `types/`. `client.ts` не содержит DTO и доменные типы.
|
||||
|
||||
```ts
|
||||
// src/infrastructure/pet-project-api/types/post.ts
|
||||
// src/infra/pet-project-api/types/post.ts
|
||||
export type PostDto = {
|
||||
id: string
|
||||
slug: string
|
||||
@@ -57,14 +57,14 @@ export type PostListQueryDto = {
|
||||
```
|
||||
|
||||
```ts
|
||||
// src/infrastructure/pet-project-api/types/index.ts
|
||||
// src/infra/pet-project-api/types/index.ts
|
||||
export type { PostDto, PostListQueryDto } from './post'
|
||||
```
|
||||
|
||||
Типы, которые нужны только базовому транспорту, можно держать отдельно:
|
||||
|
||||
```ts
|
||||
// src/infrastructure/pet-project-api/types/client.ts
|
||||
// src/infra/pet-project-api/types/client.ts
|
||||
export type QueryParams = Record<string, string | number | boolean>
|
||||
```
|
||||
|
||||
@@ -73,7 +73,7 @@ export type QueryParams = Record<string, string | number | boolean>
|
||||
Ошибка API тоже относится к REST-модулю.
|
||||
|
||||
```ts
|
||||
// src/infrastructure/pet-project-api/errors/pet-project-api.error.ts
|
||||
// src/infra/pet-project-api/errors/pet-project-api.error.ts
|
||||
export class PetProjectApiError extends Error {
|
||||
constructor(
|
||||
public readonly status: number,
|
||||
@@ -90,7 +90,7 @@ export class PetProjectApiError extends Error {
|
||||
`client.ts` содержит только транспортную оболочку и сборку инстанса. Прямой `fetch` живёт здесь, а не в компонентах и не в методах верхних слоёв.
|
||||
|
||||
```ts
|
||||
// src/infrastructure/pet-project-api/client.ts
|
||||
// src/infra/pet-project-api/client.ts
|
||||
import { PetProjectApiError } from './errors/pet-project-api.error'
|
||||
import type { QueryParams } from './types/client'
|
||||
|
||||
@@ -131,7 +131,7 @@ export class PetProjectApiClient {
|
||||
Методы группируются по сущностям в `methods/`. Они не знают про React, SWR и UI.
|
||||
|
||||
```ts
|
||||
// src/infrastructure/pet-project-api/methods/posts.ts
|
||||
// src/infra/pet-project-api/methods/posts.ts
|
||||
import type { PetProjectApiClient } from '../client'
|
||||
import type { PostDto, PostListQueryDto } from '../types/post'
|
||||
|
||||
@@ -155,7 +155,7 @@ export function postsMethods(client: PetProjectApiClient) {
|
||||
`index.ts` собирает именованный API-объект и открывает наружу только публичные части модуля.
|
||||
|
||||
```ts
|
||||
// src/infrastructure/pet-project-api/index.ts
|
||||
// src/infra/pet-project-api/index.ts
|
||||
import { PetProjectApiClient } from './client'
|
||||
import { postsMethods } from './methods/posts'
|
||||
|
||||
@@ -173,7 +173,7 @@ export type { PostDto, PostListQueryDto } from './types'
|
||||
export * from './hooks'
|
||||
```
|
||||
|
||||
Внешний код импортирует только из `infrastructure/pet-project-api`, не из внутренних файлов модуля.
|
||||
Внешний код импортирует только из `infra/pet-project-api`, не из внутренних файлов модуля.
|
||||
|
||||
## Правила
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: REST
|
||||
description: Как правильно работать с REST API в проекте.
|
||||
keywords: [rest, api, данные, infrastructure, клиент, swr, стратегии]
|
||||
keywords: [rest, api, данные, infra, клиент, swr, стратегии]
|
||||
---
|
||||
|
||||
# REST
|
||||
@@ -15,7 +15,7 @@ REST в проекте проходит через два главных эта
|
||||
|
||||
## 1. Создание клиента
|
||||
|
||||
На этом этапе внешний API оформляется как модуль слоя `infrastructure/`.
|
||||
На этом этапе внешний API оформляется как модуль слоя `infra/`.
|
||||
|
||||
Клиент отвечает за:
|
||||
|
||||
|
||||
@@ -15,13 +15,13 @@ Business-композиция используется, когда просто
|
||||
- Нужно преобразовать DTO в доменную модель.
|
||||
- Нужно спрятать бизнес-сценарий за доменным API.
|
||||
|
||||
Такая логика не пишется в `infrastructure/`. REST-клиент остаётся прозрачным адаптером к API.
|
||||
Такая логика не пишется в `infra/`. REST-клиент остаётся прозрачным адаптером к API.
|
||||
|
||||
## Пример поверх одного GET-хука
|
||||
|
||||
```ts
|
||||
// src/business/pets/hooks/use-available-pets.hook.ts
|
||||
import { useGetPetList } from 'infrastructure/pet-store-api'
|
||||
import { useGetPetList } from 'infra/pet-store-api'
|
||||
|
||||
/**
|
||||
* Доменный список доступных питомцев.
|
||||
@@ -36,13 +36,13 @@ export const useAvailablePets = () => {
|
||||
}
|
||||
```
|
||||
|
||||
`useGetPetList` — infrastructure-хук. `hasPets` — бизнес-интерпретация, поэтому она появляется в `business/pets`.
|
||||
`useGetPetList` — infra-хук. `hasPets` — бизнес-интерпретация, поэтому она появляется в `business/pets`.
|
||||
|
||||
## Пример композиции нескольких GET-хуков
|
||||
|
||||
```ts
|
||||
// src/business/pets/hooks/use-pets-dashboard.hook.ts
|
||||
import { useGetPetList } from 'infrastructure/pet-store-api'
|
||||
import { useGetPetList } from 'infra/pet-store-api'
|
||||
|
||||
/**
|
||||
* Данные dashboard по питомцам.
|
||||
@@ -64,13 +64,13 @@ export const usePetsDashboard = () => {
|
||||
}
|
||||
```
|
||||
|
||||
Композиция нескольких запросов не добавляется в `infrastructure/pet-store-api/hooks/`, потому что это уже сценарий потребления данных.
|
||||
Композиция нескольких запросов не добавляется в `infra/pet-store-api/hooks/`, потому что это уже сценарий потребления данных.
|
||||
|
||||
## Пример auth-состояния
|
||||
|
||||
```ts
|
||||
// src/business/auth/hooks/use-auth-state.hook.ts
|
||||
import { useGetCurrentUser } from 'infrastructure/backend-api'
|
||||
import { useGetCurrentUser } from 'infra/backend-api'
|
||||
|
||||
/**
|
||||
* Состояние авторизации текущего пользователя.
|
||||
@@ -107,7 +107,7 @@ src/business/
|
||||
## Что запрещено
|
||||
|
||||
```ts
|
||||
// Плохо — business-смысл внутри infrastructure-хука
|
||||
// Плохо — business-смысл внутри infra-хука
|
||||
export const useGetPetList = (status: PetStatus) => {
|
||||
const query = useSWR(...)
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ keywords: [rest, client components, swr, get-хук, client state]
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import { useGetPetList } from 'infrastructure/pet-store-api'
|
||||
import type { PetStatus } from 'infrastructure/pet-store-api'
|
||||
import { useGetPetList } from 'infra/pet-store-api'
|
||||
import type { PetStatus } from 'infra/pet-store-api'
|
||||
|
||||
const statuses: PetStatus[] = ['available', 'pending', 'sold']
|
||||
|
||||
@@ -60,7 +60,7 @@ export function PetTabs() {
|
||||
Хук добавляется в REST-модуль сервиса:
|
||||
|
||||
```text
|
||||
src/infrastructure/pet-store-api/hooks/use-get-pet-list.hook.ts
|
||||
src/infra/pet-store-api/hooks/use-get-pet-list.hook.ts
|
||||
```
|
||||
|
||||
Не создавайте локальный `useSWR` в компоненте.
|
||||
|
||||
@@ -30,7 +30,7 @@ keywords: [rest, swr, fallback, initial data, client hooks, unstable_serialize,
|
||||
## Ключ хука
|
||||
|
||||
```ts
|
||||
// src/infrastructure/pet-store-api/hooks/use-get-pet-list.hook.ts
|
||||
// src/infra/pet-store-api/hooks/use-get-pet-list.hook.ts
|
||||
export const getPetListKey = (status: PetStatus) =>
|
||||
['pet-store-api', 'pet', 'list', status] as const
|
||||
```
|
||||
@@ -46,7 +46,7 @@ import { SWRConfig, unstable_serialize } from 'swr'
|
||||
import {
|
||||
getPetListKey,
|
||||
petStoreApi,
|
||||
} from 'infrastructure/pet-store-api'
|
||||
} from 'infra/pet-store-api'
|
||||
|
||||
type PetsLayoutProps = {
|
||||
children: ReactNode
|
||||
@@ -78,7 +78,7 @@ export default async function PetsLayout({ children }: PetsLayoutProps) {
|
||||
```tsx
|
||||
'use client'
|
||||
|
||||
import { useGetPetList } from 'infrastructure/pet-store-api'
|
||||
import { useGetPetList } from 'infra/pet-store-api'
|
||||
|
||||
export function PetList() {
|
||||
const { data: pets, isLoading } = useGetPetList('available')
|
||||
|
||||
@@ -17,7 +17,7 @@ keywords: [rest, promise.all, параллельные запросы, server co
|
||||
## Хорошо
|
||||
|
||||
```tsx
|
||||
import { petStoreApi } from 'infrastructure/pet-store-api'
|
||||
import { petStoreApi } from 'infra/pet-store-api'
|
||||
import { PetsDashboardScreen } from 'screens/pets-dashboard'
|
||||
|
||||
export default async function PetsDashboardPage() {
|
||||
|
||||
@@ -19,10 +19,10 @@ keywords: [rest, promise, suspense, streaming, server components]
|
||||
```tsx
|
||||
// src/app/(routes)/pets/page.tsx
|
||||
import { Suspense } from 'react'
|
||||
import { petStoreApi } from 'infrastructure/pet-store-api'
|
||||
import { petStoreApi } from 'infra/pet-store-api'
|
||||
import { PetListSection } from 'widgets/pet-list-section'
|
||||
import { PetListSkeleton } from 'widgets/pet-list-section'
|
||||
import type { Pet } from 'infrastructure/pet-store-api'
|
||||
import type { Pet } from 'infra/pet-store-api'
|
||||
|
||||
export default function PetsPage() {
|
||||
const petsPromise = petStoreApi.pet.findPetsByStatus({ status: 'available' })
|
||||
|
||||
@@ -29,7 +29,7 @@ SSR/dynamic rendering нужен, когда данные зависят от т
|
||||
|
||||
```tsx
|
||||
// src/app/(routes)/pets/page.tsx
|
||||
import { petStoreApi } from 'infrastructure/pet-store-api'
|
||||
import { petStoreApi } from 'infra/pet-store-api'
|
||||
import { PetsScreen } from 'screens/pets'
|
||||
|
||||
export default async function PetsPage() {
|
||||
@@ -48,7 +48,7 @@ export default async function PetsPage() {
|
||||
```tsx
|
||||
// src/app/(routes)/pets/[id]/page.tsx
|
||||
import { notFound } from 'next/navigation'
|
||||
import { petStoreApi } from 'infrastructure/pet-store-api'
|
||||
import { petStoreApi } from 'infra/pet-store-api'
|
||||
import { PetDetailScreen } from 'screens/pet-detail'
|
||||
|
||||
type PetPageProps = {
|
||||
|
||||
Reference in New Issue
Block a user