, чтобы сохранить свой прогресс
Николай Ланец
12 дек. 2021 г., 16:35

Обсуждение задания "Write a Simple Counter"

В одном из решений здесь есть пример того, как точно не надо делать (хотя технически это возможно, и даже решение принято как правильное).
increment() { this.setState({ count: ++this.state.count }); } decrement() { this.setState({ count: --this.state.count }); }
Технически, эти методы делают то, чего от них и ожидалось: увеличивают и уменьшают значение состояния. Но в данном случае проблема в том, что используются операторы ++ и --. Соль обоих операторов в том, что они не просто возвращают новое значение (если они использованы перед переменной), но еще и меняют саму переменную. То есть еще до того, как реально отработался метод setState(), значение переменной this.state.count уже было изменено. И в чем же здесь проблема? А в том, что у вас в этот момент потерялась возможность среагировать на это изменение внутри своего компонента и сравнить его со старым (или новым) состоянием. В реакте в классовых компонентах есть некоторые методы специально для таких случаев, например shouldComponentUpdate, который дает возможность вам решить стоит ли ререндерить компонент в ответ на полученные изменения, и componentDidUpdate, который выполняется сразу после обновления компонента (при поступлении новых свойств или изменении состояния). Логика обоих методов в том, чтобы иметь возможность сравнить старое и новое состояние и в зависимости от изменений решить стоит ли еще что-то предпринять. Вот давайте добавим эти методы в правильно написанном классе:
shouldComponentUpdate(_props, newState) { console.log('shouldComponentUpdate oldState', { ...this.state }); console.log('shouldComponentUpdate newState', { ...newState }); return true; } componentDidUpdate(_oldProps, oldState) { console.log('componentDidUpdate oldState', { ...oldState }); console.log('componentDidUpdate newState', { ...this.state }); }
Кликнем increment и посмотрим вывод в консоль:
shouldComponentUpdate oldState {count: 0} shouldComponentUpdate newState {count: 1} componentDidUpdate oldState {count: 0} componentDidUpdate newState {count: 1}

Как мы видим, в этих методах действительно присутствуют разные значения в старом и новом состоянии. То есть здесь мы легко можем написать логику типа
if(oldState.count !== this.state.count) { // ... some logic }

А теперь сделаем вызов на неправильном компоненте и посмотрим результат:
shouldComponentUpdate oldState {count: 1} shouldComponentUpdate newState {count: 1} componentDidUpdate oldState {count: 1} componentDidUpdate newState {count: 1}

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

В общем, старайтесь избегать таких подводных камней. Это может привести к тому, что состояние изменится, а ререндеринг в DOM не выполнится, потому что старое состояние будет равно новому.

Добавить комментарий