Перейти к основному содержимому

Сегменты

Segment - третий уровень разбиения приложения, согласно назначению модуля в коде и реализации

{layer}/
├── {slice}/
| ├── ui/ # UI-логика (components, ui-widgets, ...)
| ├── model/ # Бизнес-логика (store, actions, effects, reducers, ...)
| ├── lib/ # Инфраструктурная логика (utils/helpers)
| ├── config/ # Конфигурация приложения (env-vars, ...)
| └── api/ # Логика запросов к API (api instances, requests, ...)

Общие правила

Каждый из приведенных сегментов, представляет привычные нам уровни абстракций, при разработке ПО.

Каждый из сегментов отвечает за свою область, но при этом все вместе - они формируют единый образ данного слайса и его логики, а конкретно:

  • его визуальное отображение (ui)
  • его бизнес-логику (model)
  • его вспомогательные модули (lib)

Также, в редких случаях, затрагивая:

  • его конфигурацию (config)
  • его логику работы с API-запросами (api)
tip

Каждый сегмент может быть как файлом, так и директорией - в зависимости от сложности реализуемого слайса

Т.е. вполне допустимы и такие варианты:

features/wallet/add-funds
├── ui.tsx
├── model.ts
└── index.ts
pages/home/
├── index.tsx
└── style.module.scss

ui

UI-представление модуля

Может содержать внутри:

  • Компоненты вашего UI-фреймворка (React, Vue, Angular, ...)
  • Canvas-виджеты
  • (любые другие модули ui-представления)

Примеры

Комплексный UI для слоя

{layer}/{slice}/
├── ui/
| ├── toolbar/
| | ├── title/
| | └── actions/
| ├── content/
| | ├── sort/
| | └── table/
| └── index.tsx/
{layer}/{slice}/ui/index.tsx
import Toolbar from "./toolbar";
import Content from "./content";
import styles from "./styles.module.scss";

export const SomeForm = () => (
<Layout className={styles.root}>
<Toolbar className={styles.toolbar} />
<Content className={styles.content} />
</Layout>
)

model

Бизнес-логика модуля

Может содержать:

  • Логику создания и обновления мини-стора под этот слайс
    • В мире effector: createStore + createDomain
    • В мире redux: createSlice
  • Список событий, обрабатываемых моделью родительского слайса, и обновляющих его состояние
    • В мире effector: events
    • В мире redux: actions + dispatch
  • Список асинхронных сайд-эффектов, для подгрузки данных и прочих асинхронных операций
    • В мире effector: effects
    • В мире redux: thunks / sagas / epics
  • Список селекторов/контрактов/хуков для использования состояния слайса
    • В мире effector: useStore, ...
    • В мире redux: useSelector, selectors

lib

Вспомогательные библиотеки

Обычно содержит набор утилит, помогающих написанию логики и распределенных по группам, т.е. отдельным библиотекам.

api

Логика взаимодействия с API

Обычно содержит

  • инстансы для работы с разными внешними API
  • методы / фабрики для вызова конкретных эндпоинтов

В редких случаях (react-query / graphql) сами запросы могут лежать рядом с местом использования

  • Но чаще всего рекоммендуется располагать API-сегмент в shared-слое, чтобы снизить количество переплетений логики

При этом, данный сегмент может как писаться вручную, так и генерироваться с помощью схемы API

  • Например с помощью openapi-generator, swagger-codegen

Примеры

**/**/api/user.ts
export class UserApi {
constructor(config) {...}
getList(params: GetListParams): Promise<User[]> {...}
...
}
**/**/model/thunks.ts
import { userApi } from "shared/api"

// Создание инстансов API может происходить
// как на месте использования, так и в самом API-сегменте
//
// const userApi = new UserApi();

export const getUserListThunk = createAsyncThunk("...", (params) => {
return userApi.getList(params);
});

config

Модуль конфигурации приложения и его окружения

Обычно содержит конфигурацию приложения и методы, для работы с ним

Примеры

Использование переменных окружения

Реализация зависит от проекта и команды, здесь приведен лишь один из вариантов

shared/config/index.ts
export const isDevEnv = NODE_ENV === "development";
export const OAUTH_TOKEN = getEnvVar("REACT_APP_OAUTH_TOKEN");
**/**/index.tsx
import { OAUTH_TOKEN, isDevEnv } from "shared/config";

export const OAuthProvider = () => (
<OAuth
debug={isDevEnv}
token={OAUTH_TOKEN}
...
/>
)

См. также

WIP: Со временем будут появляться статьи по каждой абстракции

[01/12] logo-mini