Skip to content

Одна логика, несколько представлений

Задача

Переиспользовать один слой бизнес-логики в нескольких UI-представлениях.

Решение

Держать логику в одной view model и позволять разным views потреблять один и тот же публичный контракт.

Код

ts
import { declareViewModel, readonlyAtom } from '@nrgyjs/core';

export const InboxViewModel = declareViewModel(({ scope }) => {
  const unreadCount = scope.atom(3);

  return {
    state: {
      unreadCount: readonlyAtom(unreadCount),
    },
    markAllRead: () => unreadCount.set(0),
  };
});
tsx
import { useAtom } from '@nrgyjs/react';
import { withViewModel } from '@nrgyjs/react';

const InboxBadge = withViewModel(InboxViewModel)(({ viewModel }) => {
  const unreadCount = useAtom(viewModel.state.unreadCount);

  return <span>{unreadCount}</span>;
});

const InboxPage = withViewModel(InboxViewModel)(({ viewModel }) => {
  const unreadCount = useAtom(viewModel.state.unreadCount);

  return (
    <section>
      <h1>Unread: {unreadCount}</h1>
      <button onClick={viewModel.markAllRead}>Mark all read</button>
    </section>
  );
});

На что обратить внимание

  • публичный контракт должен оставаться маленьким и UI-agnostic
  • в общую логику не стоит рано протаскивать view-specific formatting
  • переиспользовать нужно логику, а не отрендеренную разметку

Частые ошибки

  • дублировать один и тот же workflow для каждого экрана или виджета
  • слишком рано добавлять во view model presentation-specific fields
  • жёстко привязывать переиспользуемую логику к одному framework-specific компоненту