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

Практические примеры решений

Пример 1: Добавление лайка к статье

Вопрос: Где разместить логику добавления/удаления лайка?

// ✅ Хорошо - пользовательский сценарий в features/
// features/article-favorite/model/use-toggle-favorite.ts
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { invalidateArticleListRelatedQueries } from '@/entities/article';
import { favoriteArticle, unfavoriteArticle } from '@/shared/api/endpoints/article.api';

export function useToggleFavorite(slug: string) {
const queryClient = useQueryClient();

return useMutation({
mutationFn: (isFavorited: boolean) =>
isFavorited ? unfavoriteArticle(slug) : favoriteArticle(slug),
onSuccess: () => {
invalidateArticleListRelatedQueries(queryClient);
}
});
}

// features/article-favorite/ui/favorite-button.tsx
import { useTranslations } from 'next-intl';
import { useToggleFavorite } from '../model/use-toggle-favorite';
import type { Article } from '@/entities/article';

interface FavoriteButtonProps {
record: Article;
}

export function FavoriteButton({ record }: FavoriteButtonProps) {
const { mutate } = useToggleFavorite(record.slug);
const t = useTranslations('common');

const handleToggleFavorite = () => {
mutate(record.favorited);
};

return (
<button onClick={handleToggleFavorite}>
{t('actions.favor', {
isFavorite: record.favorited
})}
<span>{record.favoritesCount}</span>
</button>
);
}

Почему features/?

  • Это законченный пользовательский сценарий
  • Управляет состоянием и обработкой ошибок
  • Может быть переиспользован на разных страницах

Пример 2: Валидация email

Вопрос: Где разместить валидацию email?

// ❌ Плохо - в entities/user (если валидация не специфична для сущности User)
// entities/user/lib/validate-email.ts
export function validateEmail(email: string) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}

// ✅ Хорошо - в shared/lib (техническая утилита)
// shared/lib/validation/email.ts
export function isValidEmail(email: string): boolean {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}

// Использование в features
// features/auth/model/validation.ts
import { isValidEmail } from '@/shared/lib/validators/email';
import { z } from 'zod';

export const createLoginSchema = (t: TFunction) => z.object({
email: z.string().refine(isValidEmail, t('errors.invalidEmailFormat')),
});

Почему shared/?

  • Это техническая утилита, а не бизнес-логика
  • Не содержит доменных правил
  • Переиспользуется в разных контекстах