Робіть return, як тільки знайшли відповідь
Працюючи з React-проектами, я зіткнувся з повторюваної проблемою: render-функції, які складно зрозуміти. Я хотів би розповісти про найбільш частої причини даного ускладнення — вкладені if-else оператори в render-функції, і як цього можна уникнути.
Що таке render-функція?
Відштовхнемося від React-документації . Render-функція повинна повертати React Element або нульове значення. В ідеалі вона повинна бути чистою і використовувати тільки this.props і this.state .
Навіщо потрібен умовний оператор в render-функції?
В чистій render-функції умовний оператор звичайно заснований на стані/параметри компонента. Є дві основні причини if-перевірок:
- Чи є у нас всі необхідні дані?
if (this.props.user) { // Є дані, відображаємо компонент юзера } else { // Немає даних юзера }
- Різні варіанти відображення на підставі state/props.
if (this.props.showWarning) { // Додатково потрібно відобразити компонент з попередженням }
Але не можна сказати, що наявність умовних операторів в render-функції саме по собі погано або добре. Проблема полягає саме в організації таких перевірок.
Погана організація
Давайте перейдемо до прикладу:
render() { let content; if (this.props.users) { if (this.props.users.length) { content = ( <List> {this.props.users .map(user => <UserCard key={user.id} user={user} />)} </List> ); } else { content = <Warning>Empty</Warning>; } } else { content = <Loading />; } return content; }
Виглядає важкувато. Спробуємо спростити:
render() { if (!this.props.users) { return <Loading />; } if (!this.props.users.length) { return <Warning>Empty</Warning>; } return ( <List> {this.props.users .map(user => <UserCard key={user.id} user={user} />)} </List> ); }
Які переваги ми отримуємо?
Читабельність
Основне завдання нашої функції — це відображення списку користувачів. І після простого рефакторінгу ми з легкістю можемо зосередитися саме на цій частині. Чому? Тому що тепер у неї немає ніяких вкладень і нам не потрібно замислюватися: «чи Всі дані представлені?». Ми зробили всі необхідні перевірки у верхній частині, тому помилок бути не повинно. Це знижує когнітивну навантаження і дозволяє зосередитися на оптимістичній частини коду (happy path ). Ми також можемо сказати, що логіка візуалізації користувачів є ізольованою і візуально виділяється , і те ж можна сказати про кожну захисної перевірці.
Менше помилок і похибок
Нам не потрібно працювати з глибокої вкладеністю, що зменшує ймовірність помилки з дужками. Якщо код стає легкочитаемым і зрозумілим, знайти в ній помилку набагато простіше.
Недоліки?
Немає жодних недоліків! Але не всі зі мною погодяться. Часто люди бачать проблему в тому, що кількість операцій повернення зростає, а функція повинна бути одна точка виходу. Але якщо копнути , хто і чому це придумав, то в основному всі дороги ведуть до правилом Single Entry — Single Exit.
Single Entry — Single Exit
Тут проблема полягає в тому, що принцип Single Entry — Single Exit використовується для запобігання входу в функцію оператором GO-TO . Суть окремого виходу полягає в тому, що функція повертається в єдине місце, а не стрибає за допомогою GO-TO в якусь іншу частину програми, ніколи не досягнувши поворотного значення. Крім того, ніде не сказано, як багато зворотних значень у вас може бути. Принцип Single Entry — Single Exit сформулював Эдсгер Ст. Дейкстра , який рішуче виступає проти практики використання операторів GO-TO.
Що ще?
У книзі Code complete написано наступне:
Але, крім цього, у книзі також сказано:
Як раз в нашому випадку множинний повернення доречний через поліпшення читабельності.
Також у книзі є окрема глава про рефакторинге і перелік його видів/причин, один з яких я хотів би підкреслити.
«Повернення з методу відразу після отримання відповіді замість установки повертається всередині вкладених операторів ifthenelse»Вихід з методу відразу ж після знаходження значення, що повертається часто допомагає полегшити читання коду і знизити ймовірність помилок. Альтернативний варіант — установка значення, що повертається, і слідування до виходу з методу через затори операторів — може виявитися більш складним".
Є ще два схожих патерну, які мені вдалося знайти, — Guard Clause і Bouncer Pattern . Вони виглядають приблизно так само, як описаний випадок.
Залишайте свою думку в коментарях!
Опубліковано: 06/06/17 @ 10:00
Розділ Різне
Рекомендуємо:
Українці в екосистемі Facebook
Python digest #14: Python обганяє PHP StackOverflow. Event loop in Rust
Прогнозування часових рядів за допомогою Prophet від Facebook
10 плюсів роботи в ніші ЕСЕЙ баксовыми виплатами
Інфо-сайти: підсумки травня 2017 рекорд по трафіку і кількості опублікованих статей