Files
twenty/packages/twenty-docs/l/ru/developers/contribute/style-guide.mdx
T
f018f17133 i18n - docs translations (#19970)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-04-22 14:44:57 +02:00

177 lines
6.3 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Руководство по стилю
icon: кисть
description: Соглашения по коду и лучшие практики для внесения вклада в Twenty.
---
## React
### Только функциональные компоненты
Всегда используйте функциональные компоненты TSX с именованными экспортами.
```tsx
// ❌ Bad
const MyComponent = () => {
return <div>Hello World</div>;
};
export default MyComponent;
// ✅ Good
export function MyComponent() {
return <div>Hello World</div>;
};
```
### Свойства
Создайте тип с именем `{ComponentName}Props`. Используйте деструктуризацию. Не используйте `React.FC`.
```tsx
type MyComponentProps = {
name: string;
};
export const MyComponent = ({ name }: MyComponentProps) => <div>Hello {name}</div>;
```
### Не используйте спред одного объекта пропсов
```tsx
// ❌ Bad
const MyComponent = (props: MyComponentProps) => <Other {...props} />;
// ✅ Good
const MyComponent = ({ prop1, prop2 }: MyComponentProps) => <Other {...{ prop1, prop2 }} />;
```
## Управление состоянием
### Атомы Jotai для глобального состояния
```tsx
import { createAtomState } from '@/ui/utilities/state/jotai/utils/createAtomState';
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
export const myAtomState = createAtomState<string>({
key: 'myAtomState',
defaultValue: 'default value',
});
```
* Предпочитайте атомы вместо проброса пропсов
* Не используйте `useRef` для состояния — используйте `useState` или атомы
* Используйте семейства атомов и селекторы для списков
### Избегайте лишних повторных рендеров
* Выносите `useEffect` и загрузку данных в соседние сайдкар-компоненты
* Предпочитайте обработчики событий (`handleClick`, `handleChange`) вместо `useEffect`
* Не используйте `React.memo()` — вместо этого исправьте первопричину
* Ограничьте использование `useCallback` или `useMemo`
```tsx
// ❌ Bad — useEffect in the same component causes re-renders
export const Page = () => {
const [data, setData] = useAtomState(dataState);
const [dep] = useAtomState(depState);
useEffect(() => { setData(dep); }, [dep]);
return <div>{data}</div>;
};
// ✅ Good — extract into sibling
export const PageData = () => {
const [data, setData] = useAtomState(dataState);
const [dep] = useAtomState(depState);
useEffect(() => { setData(dep); }, [dep]);
return <></>;
};
export const Page = () => {
const [data] = useAtomState(dataState);
return <div>{data}</div>;
};
```
## TypeScript
* **`type` вместо `interface`** — более гибкий, проще компоновать
* **Строковые литералы вместо перечислений** — за исключением перечислений из GraphQL codegen и внутренних API библиотеки
* **Без `any`** — строгий режим TypeScript обязателен
* **Без type-импортов** — используйте обычные импорты (принудительно через Oxlint `typescript/consistent-type-imports`)
* **Используйте [Zod](https://github.com/colinhacks/zod)** для проверки во время выполнения нетипизированных объектов
## JavaScript
```tsx
// Use nullish-coalescing (??) instead of ||
const value = process.env.MY_VALUE ?? 'default';
// Use optional chaining
onClick?.();
```
## Именование
* **Переменные**: camelCase, информативные (`email`, а не `value`, `fieldMetadata`, а не `fm`)
* **Константы**: SCREAMING_SNAKE_CASE
* **Типы/Классы**: PascalCase
* **Файлы/директории**: kebab-case (`.component.tsx`, `.service.ts`, `.entity.ts`)
* **Обработчики событий**: `handleClick` (не `onClick` для функции-обработчика)
* **Пропсы компонента**: используйте префикс имени компонента (`ButtonProps`)
* **Стилизованные компоненты**: префикс `Styled` (`StyledTitle`)
## Стилизация
Используйте стилизованные компоненты [Linaria](https://github.com/callstack/linaria). Используйте значения темы — избегайте жестко заданных `px`, `rem` или цветов.
```tsx
// ❌ Bad
const StyledButton = styled.button`
color: #333333;
font-size: 1rem;
margin-left: 4px;
`;
// ✅ Good
const StyledButton = styled.button`
color: ${({ theme }) => theme.font.color.primary};
font-size: ${({ theme }) => theme.font.size.md};
margin-left: ${({ theme }) => theme.spacing(1)};
`;
```
## Импорт
Используйте алиасы вместо относительных путей:
```tsx
// ❌ Bad
import { Foo } from '../../../../../testing/decorators/Foo';
// ✅ Good
import { Foo } from '~/testing/decorators/Foo';
import { Bar } from '@/modules/bar/components/Bar';
```
## Структура папок
```
front
└── modules/ # Feature modules
│ └── module1/
│ ├── components/
│ ├── constants/
│ ├── contexts/
│ ├── graphql/ (fragments, queries, mutations)
│ ├── hooks/
│ ├── states/ (atoms, selectors)
│ ├── types/
│ └── utils/
└── pages/ # Route-level components
└── ui/ # Reusable UI components (display, input, feedback, ...)
```
* Модули могут импортировать из других модулей, но `ui/` должен оставаться без зависимостей
* Используйте подпапки `internal/` для приватного кода модуля
* Компоненты — до 300 строк, сервисы — до 500 строк