Практические примеры решений
Пример 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/?
- Это техническая утилита, а не бизнес-логика
- Не содержит доменных правил
- Переиспользуется в разных контекстах