Если состояние ReactJS имеет свойство карты, изменение значения карты не отражает состояние - PullRequest
0 голосов
/ 16 марта 2019

У меня есть компонент с именем Counters

export default class Counters extends Component {
  state = {
    counterMap: {}
  };
  noOfComponents = 5;

  componentWillMount() {
    var counterMap = new Map();
    for (var i = 0; i < this.noOfComponents; i++) {
      var counter = {
        id: i + 1,
        value: i + 1,
        key: i + 1
      };
      counterMap.set(i + 1, counter);
    }
    this.setState({ counterMap });
  }

  handleDecrease = counterId => {
    // This is always Called from the inner child... Verified !
    const { counterMap } = this.state;
    const counter = counterMap.get(counterId);
    counter.value = counter.value - 1;
    counterMap.delete(counterId);
    counterMap.set(counterId, counter);
    this.setState({ counterMap: counterMap });
  };

  render() {
    const counterComps = [];
    this.state.counterMap.forEach(element => {
      const counter = (
        <Counter
          data={element}
          onDecrease={this.handleDecrease}
          onIncrease={this.handleIncrease}
        />
      );
      counterComps.push(counter);
    });
    return <div>{counterComps}</div>;
  }
}

Моя проблема

handleDecrease = counterId => {
  // This is always Called
  const { counterMap } = this.state;
  const counter = counterMap.get(counterId);
  counter.value = counter.value - 1;
  counterMap.delete(counterId);
  counterMap.set(counterId, counter);
  this.setState({ counterMap: counterMap });
}

Это не работает в пользовательском интерфейсе.

Изменение значения счетчика неотражать в пользовательском интерфейсе.Я думаю, потому что сама карта никогда не менялась, а менялись только значения ... и поэтому Реакция Думает, что состояние никогда не менялось !!! .Это правильная причина.Я не хочу использовать массив.Если я использую массивы для счетчиков, код работает абсолютно нормально.

Что мне здесь не хватает?

1 Ответ

2 голосов
/ 16 марта 2019

Вы должны всегда обновлять состояние или любое из его полей:

handleDecrease = counterId => {
  // This is always Called
  this.setState(prevState => {
      const { oldCounterMap } = prevState;
      newCounterMap = new Map(oldCounterMap);
      const counter = oldCounterMap.get(counterId);
      newCounterMap.set(counterId, {...counter, value: counter.value - 1});
      return Object.assign({}, prevState, { counterMap: newCounterMap })
  });
}

Пояснение:

Прежде всего, если вам нужно вычислить новое значение состояния на основе старого значения, вам следует использовать эту сигнатуру setState: setState(previousState => {}), которая передает вам текущее состояние в качестве аргумента.

Затем, чтобы постоянно обновлять счетчик, нам сначала нужно клонировать таблицу счетчиков:

newCounterMap = new Map(oldCounterMap);

Вы можете видеть, что это клон, потому что newCounterMap === oldCounterMap это false.

Затем мы продолжаем и обновляем эту карту, как нам нравится:

newCounterMap.set(counterId, {...counter, value: counter.value - 1});

Обратите внимание на расширение объекта, которое снова вызывает создание целого нового объекта на основе counter (это просто хорошая практика, даже если это не является критически необходимым).

И, наконец, мы возвращаем новый объект, чтобы заменить наше текущее состояние.

return Object.assign({}, prevState, { counterMap: newCounterMap })

Опять же, обратите внимание, что я использовал растяжение объектов здесь, так что мы оба возвращаем новый объект, а также оставляем другие значения без изменений (не перезаписываем другие записи state)

...