Подписаться на блог

Ошибки state-менеджмента React-компонентов

При работе с React у многих разработчиков, у которых с ним менее года опыта (или более, но понимания некоторых аспектов нет) возникает проблема с пониманием состояния компонента.

Когда были классовые компоненты, многие хранили в стейте вообще все, даже какие-то служебные флаги, которые можно было бы в this записать, и которые на рендер компонента никак не влияют.

Это было проблемой, но решалась она быстро. С появлением хуков ситуация ухудшилась.

Если в классовых компонентах каждый метод — какой-то шаг лайфсайкла, то с хуками концепция и подход абсолютно другой. Отсюда вырастает много ляпов, которые не сразу заметны и которые разработчики объяснить не могут, но проблемы, возникающие из-за таких ляпов превращаются в серьезную головную боль.

Парочка самых распространенных, что я видел: Эффект, который слушает проп и обновляет в след за ним стейт без каких-либо преобразований. Что-то вроде такого:

const component = ({ prop }) => {
  const [savedProp, setSavedProp] = useState(null);

  useEffect(() => {
    setSavedProp(prop);
  }, [prop]);
};

Больше логики никакой, никаких подводных камней. Мало того, что можно было бы прямо в useState прокидывать проп, так все гораздо проще — можно было бы использовать сам этот проп, вместо его сохранения в стейт! Вероятно, там когда-то был какой-то процессинг, может быть, какие-то условия, но больше этого нет, зато есть несколько ненужных обновлений компонента.

Эффект, который слушает изменения стейта, чтобы… вызвать коллбэк.

const component = ({ prop, onPropChange }) => {
  const [savedProp, setSavedProp] = useState(null);

  useEffect(() => {
    onPropChange(savedProp);
  }, [savedProp]);

  return (
    <Child prop={prop} onPropChange={setSavedProp} />
  )
};

Тут все вроде бы тоже понятно, но стейт не используется ни для чего, кроме триггера коллбэка. Правильнее прокинуть просто коллбэк и… все, а не триггерить несколько апдейтов просто так. Так мало того, часто забывают что-то еще в зависимости эффекта прокинуть, и он работает совсем не так, как должен.

Почему-то за последние полгода столкнулся с кучей таких ошибок, и не только я — в различных чатиках тоже проскакивало частенько. То ли дело в разработчиках, то ли в хуках.