Мужайтесь: из всей жути React ничто и близко не сравнится с этой.

Обычно состояние обновляется в обработчиках событий. Но иногда его нужно изменить после отображения, например переменную состояния при изменении свойства.

Этого не требуется, если:

  • нужное значение вычисляется из текущих свойств или другого состояния  —  тогда избыточное состояние полностью удаляется;
  • нужно сбросить состояние всего дерева компонентов  —  тогда компоненту передается другой ключ;
  • соответствующее состояние целиком обновляется в обработчиках событий.

Но что делать, если все это не ваш случай? Обновлять состояние при изменении свойства в эффекте, как это делают опытные разработчики React?

А вот и нет! В новой документации явно указывается, что эффект для этого не годится: с ним дочернее дерево отображается повторно, чего желательно избегать. Но какой ценой?

Вместо него рекомендуется, по-моему, самый уродливый шаблон в React. Посмотрите сами:

function CountLabel({ count }) {
const [prevCount, setPrevCount] = useState(count);
const [trend, setTrend] = useState(null);
if (prevCount !== count) {
setPrevCount(count);
setTrend(count > prevCount ? 'increasing' : 'decreasing');
}
return (
<>
<h1>{count}</h1>
{trend && <p>The count is {trend}</p>}
</>
);
}

Состояние здесь задается в функции рендеринга, нарушая, пожалуй, важнейшее правило React: функция рендеринга должна быть чистой.

Чтобы не быть голословным, привожу во всех подробностях описанное в документации.

Состояние текущего отображаемого компонента обновляется только так. Вызов функции set другого компонента во время отображения  —  ошибка. Нарушать правила чистых функций нельзя  —  это особый случай. <…>
 
Этот шаблон может быть труден для понимания, его обычно лучше избегать. <…>

Выполнение остальной части функции компонента продолжится (с выброшенным результатом). Если ваше условие ниже всех вызовов хуков, добавьте внутри нее ранний return;  —  повторное отображение запустится раньше.
 
Book of Reactions, 23:20

Здесь даже указывается на ранний return внутри оператора if, которым в функции рендеринга задается состояние.

Конечно, можно проигнорировать новую документацию и использовать эффект только потому, что он намного удобнее для восприятия.

Утешает одно  —  ничего уродливее в React нет.

Этот шаблон существовал с момента появления хуков и теперь наверняка будет рекомендоваться чуть больше, учитывая стремление команды React к сокращению нежелательного применения эффектов.

А может, уродство  —  это достоинство, раз нам рекомендуют полностью изменить код, включив в него лучшие альтернативы? Ведь, «изменяя состояние после отображения», всегда получаешь трудный для понимания код.

Когда-нибудь мы привыкнем к этому шаблону и посчитаем его красивым.

Читайте также:

Читайте нас в TelegramVK и Дзен


Перевод статьи Sebastian Carlos: The Ugliest Pattern In React

Предыдущая статьяКак вызвать из C# генерируемую на Rust библиотеку
Следующая статья25 основных вопросов для собеседования с Android-разработчиком. Часть 2