Состояние init без конструктора в реакции

import React, { Component } from 'react';

class Counter extends Component {
  state = { value: 0 };

  increment = () => {
    this.setState(prevState => ({
      value: prevState.value + 1
    }));
  };

  decrement = () => {
    this.setState(prevState => ({
      value: prevState.value - 1
    }));
  };

  render() {
    return (
      <div>
        {this.state.value}
        <button onClick={this.increment}>+</button>
        <button onClick={this.decrement}>-</button>
      </div>
    )
  }
}

Обычно я видел, что люди делают this.state в функции конструктора, если он использовал класс es6. Если он не, он, вероятно, ставит государство, используя функцию getinitialstate. Но над кодом (да это рабочий код), не использовал ни то, и другое. У меня есть 2 вопроса, что здесь здесь? является локальной переменной? если да, то почему у него нет const? откуда происходит превалирование? почему функция стрелок используется в setState? не так просто сделать this.setState({value:'something'})?

Ответ 1

О вопросе 2, см. Дан, отличный ответ здесь: Нужно ли мне использовать перегрузку setState (function) в этом случае?


  • Нет, это не локальная переменная. Это то же самое, что объявление this.state в конструкторе.

  • Да, в этом случае вы можете просто использовать this.setState({ value: this.state.value + 1 }), результат будет таким же.

Но обратите внимание, что с помощью функционального setState вы можете получить некоторые преимущества:

  • функция setState может быть повторно использована, если вы объявите ее снаружи:

    const increment = prevState => ({
      value: prevState.value + 1
    })
    

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

    this.setState(increment)
    
  • Реагирует squashes на несколько setState и выполняет их в пакетном режиме. Это может привести к неожиданному поведению. См. Следующий пример:

    http://codepen.io/CodinCat/pen/pebLaZ

    add3 () {
      this.setState({ count: this.state.count + 1 })
      this.setState({ count: this.state.count + 1 })
      this.setState({ count: this.state.count + 1 })
    }
    

    выполнение этой функции count будет только плюс 1

    Если вы используете функциональный setState:

    http://codepen.io/CodinCat/pen/dvXmwX

    const add = state => ({ count: state.count + 1 })
    this.setState(add)
    this.setState(add)
    this.setState(add)
    

    count будет +3, как вы ожидали.

Вы можете увидеть документы здесь: https://facebook.github.io/react/docs/react-component.html#setstate

Ответ 2

У меня есть 2 вопроса, что здесь state?

Свойство экземпляра, например, установка this.state = {value: 0}; в конструкторе. Он использует предложение Public Class Fields в настоящее время на этапе 2. (Итак, increment и decrement, которые являются полями экземпляров, значениями которых являются стрелка функции, поэтому они закрываются на this.)

- локальная переменная?

Нет.

откуда берется prevState? почему функция стрелок используется в setState? не так просто сделать this.setState({значение: 'something'})?

Из документация:

React может выполнять несколько вызовов setState() в одно обновление для производительности.

Поскольку this.props и this.state могут обновляться асинхронно, вы не должны полагаться на их значения для вычисления следующего состояния.

Например, этот код может не обновить счетчик:

// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});

Чтобы исправить это, используйте вторую форму setState(), которая принимает функцию, а не объект. Эта функция получит предыдущее состояние в качестве первого аргумента и реквизит в момент применения обновления в качестве второго аргумента:

// Correct
this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment
}));

... это именно то, что делает котируемый код. Это было бы неправильно:

// Wrong
increment = () => {
  this.setState({
    value: this.state.value + 1
  });
};

... потому что он полагается на состояние this.state, которое выше не говорит нам; поэтому цитируемый код делает это вместо:

increment = () => {
  this.setState(prevState => ({
    value: prevState.value + 1
  }));
};

Здесь доказательство того, что React может прерывать вызовы неочевидным образом и почему нам нужно использовать обратную версию setState: Здесь мы имеем increment и decrement, вызываемые дважды за клик, а не один раз ( один раз кнопкой, один раз по диапазону, содержащему кнопку). При щелчке + один раз нужно увеличить счетчик до 2, потому что increment вызывается дважды. Но поскольку мы не использовали функцию обратного вызова функции setState, это не так: один из этих вызовов в increment становится no-op, потому что мы используем устаревшее значение this.state.value:

class Counter extends React.Component {
  state = { value: 0 };

  increment = () => {
    /*
    this.setState(prevState => ({
      value: prevState.value + 1
    }));
    */
    console.log("increment called, this.state.value = " + this.state.value);
    this.setState({
      value: this.state.value + 1
    });
  };
  
  fooup = () => {
    this.increment();
  };

  decrement = () => {
    /*
    this.setState(prevState => ({
      value: prevState.value - 1
    }));
    */
    console.log("decrement called, this.state.value = " + this.state.value);
    this.setState({
      value: this.state.value - 1
    });
  };
  
  foodown = () => {
    this.decrement();
  };

  render() {
    return (
      <div>
        {this.state.value}
        <span onClick={this.fooup}>
          <button onClick={this.increment}>+</button>
        </span>
        <span onClick={this.foodown}>
          <button onClick={this.decrement}>-</button>
        </span>
      </div>
    )
  }
}

ReactDOM.render(
  <Counter />,
  document.getElementById("react")
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>