React создание нового state состояния в корневом компоненте зависящим от состояния другого элемента

Помогите, пожалуйста, разобраться с состояниями в классовом компоненте, пока что нуб в React, такой пример

   import React from "react";
import "./styles.css";
import users from "./data";

class App extends React.Component {
  constructor(props) {
super(props);
this.state = {
  //// Data about some user
  userId: users[0].id,
  userName: users[0].name,
  bonusesStatus: users[0].bonusesStatus
};
  }

  /// Почему если занести значение сюда.
  ///
  /// this.state.unavailableBonuses = Object.values(bonusesStatus).filter(function (el) {
  ///     return el.isAccess === false
  /// }).length
  ///
  /// То оно не сработает ?

  render() {
let bonusesStatus = this.state.bonusesStatus;

if (bonusesStatus !== undefined) {
  this.state.unavailableBonuses = Object.values(bonusesStatus).filter(
    function (el) {
      return el.isAccess === false;
    }
  ).length;
}

return (
  <div>number of unavailable bonuses - {this.state.unavailableBonuses}</div>
);
  }
}

export default App;

Имеются данные с сервера (data), на их основе мне в корневой компонент App необходимо сохранить состояние количества Недоступных бонусов this.state.unavailableBonuses оно может меняться в зависимости от изменений значения isAccess соответствующего бонуса. Вопрос - Почему если я пытаюсь создать состояние, до render() компилятор этого не разрешает (закомиченый код) ... Возможно ли просчет unavailableBonuses занести в общее хранилище this.state компонента App ?


Ответы (1 шт):

Автор решения: Daniil Loban

Основная причина в неправильном понимании стейта. Следует использовать setState() - единственно легальный способ в React для изменения стейта в классовом компоненте. Если говорить очень упрощенно то React должен знать когда состояние компонента меняется и менно вызывая предназначенный для этого метод мы сообщаем об ихменениях. Если копнуть чуть глубже то state это не просто свойство нашего класса это свойство React.Component которое мы можем проинициализирова в конструкторе как обычную переменную, но далее мы должны действовать по правилам Reacta. Попытка повлиять на state другими способами не гарантирует эффекта. Более того время применения setState так же выбирает React, мы лишь "добавляем в очередь изменения в состоянии компонента" вызывая этот метод.

Обновление можно организовать в методе componentDidMount(), наш код обязательно должен быть заключен в метод (раз мы работаем с классовым а не функциональным компонентом)

componentDidMount(){
  this.setState((state) => { // получаем текущее состояние стейта
    let bonusesStatus = state.bonusesStatus;
    if (bonusesStatus !== undefined) {
      let unavailableBonuses = Object
        .values(bonusesStatus)
        .filter(el => el.isAccess === false)
        .length;
      return {...state, unavailableBonuses};  // меняем стейт         
    } else {
      return state // оставляем стейт без изменений
    }
  })
}  
→ Ссылка