TGViewer
Дивовижний світ веброзробки Дивовижний світ веброзробки @babichdev · 2.91K subscribers
Post #107 1.95K
#мої_кращі_практики

One hook to rule them all
Мене завжди бентежив підхід, коли компонент бере на себе й логіку, і ефекти, і обробку стану — усе підряд.

Десь ми беремо якісь дані, створюємо змінні з похідними станами, описуємо колбеки і хендлери, ефекти і тому подібне. І якщо описувати це в самому компоненті, то він перетворюється на чорну скриньку, бо тоді єдине місце, де ми можемо перевірити чи правильні значення у нас у стейті — це відображення цих даних в HTML.

І це мені дуже не подобається. Бо я вважаю, що логіку треба тестувати окремо, як логіку, а в самому компоненті ми маємо перевіряти лише те, чи вірно відображаються дані в залежності від різних станів.

Тому я користуюсь далеко не інноваційним, не оригінальним, проте дуже зручним підходом state hook. Він полягає в тому, що усі сторонні дані, які потрібні компоненту, я отримую й обробляю в хуці, який має назву use<ComponentName>State.

І повертає цей хук виключно стан, який необхідний для рендеру UI. Таким чином компонент отримує виключно ті дані, які будуть в JSX. І навіть якщо для цього стану потрібен якийсь інший, сам компонент про них не знатиме.

Це дозволяє дуже чітко розділити відповідальності — всередині стейт-хука я роблю усі обчислення, перетворення за необхідності, створюю усі хендлери та ініціалізую всі ефекти, а UI-компонент просто перетворює цей "зліпок" на інтерфейс.

function useComponentState() {
const [filter, setFilter] = useState('');
const { data, isLoading } = useSomeFetch(filter);
const isDisabled = isLoading || !data?.length;
const displayList = useMemo(() => {
return data.map(doSomeStuff);
}, [data]);

const onInputChange = useCallback((event) => {
setFilter(trim(event.target.value));
});

return {
filter,
displayList,
isDisabled,
onInputChange
}
}

function Component() {
const {
filter,
displayList,
isDisabled,
onInputChange
} = useComponentState();

return (
<>
<input value={filter} onChange={onInputChange} />
<List items={displayList} />
<button disabled={isDisabled}>Click me</button>
</>
)
}


Що це мені дає? По-перше, розділення відповідальностей. По-друге — компонент перестає бути чорною скринькою і перетворюється на абсолютно прямолінійну систему.

Це полегшує тестування. Бо я тепер можу тестувати суто стейт-хук як юніт, перевіряючи значення замість відображення. А саме відображення можна потестувати просто замокавши цей хук кількома потрібними "снапшотами" стану.

Це полегшує контроль за залежностями компонента, бо у нього вона стає лише одна. А залежності стейт-хука це вже геть інша історія.

Я не скажу, що це срібна куля і панацея, яка вирішує усі проблеми. Бо навіть інтеграційні тести все одно вимагатимуть від нас перевірки різних сценаріїв на відображенні. Але на рівні суто компонента такий підхід суттєво мені спростив роботу. Як мінімум, я не харюсь через те, що всередині компонента купа заплутаної логіки, бо її там просто немає.

Взагалі це лише частина загального підходу з розділення логіки на декілька шарів, зокрема аж на чотири, який я запропонував команді, і який знайшов дуже теплий відгук серед колег.

Цікавить, як це працює на рівні чотирьох шарів? Дайте знати в коментарях — розповім про весь підхід, який у нас суттєво покращив якість як суто коду, так і побудови наших інтерфейсів.

@babichdev
  • ❤ 69
  • 🔥 20
  • 🤔 4
More from @babichdev
  1. Sep 30, 2026Товариство, запрошую вас цієї суботи, 3 жовтня, на Fwdays Tech Summit — онлайн конференцію…
  2. Sep 28, 2026#збір_на_авто_для_21 Товариство, почнімо тиждень з доброго діла. Я би дуже хотів, аби ми ц…
  3. Sep 27, 2026Знайшов своє старезне резюме. Аж пустив скупу сльозу за тими часами, коли навіть з таким м…
  4. Sep 25, 2026Днями на редіті побачив допис, в якому автор питав, чому його лічильник часу на сторінці з…
  5. Sep 23, 2026Який ШІ найкращий для навчання? Відповідь проста — той, з яким ви чогось навчились. ШІ це…
  6. Sep 18, 2026Оце я, канєшна, провтикав. Конфа завтра, 19 вересня. Ще встигаєте взяти квиточок.
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →