Подтвердить что ты не робот

Компонент React не перерисовывается при изменении состояния

У меня есть класс React, который собирается API для получения контента. Я подтвердил, что данные возвращаются, но это не повторный рендеринг:

var DealsList = React.createClass({
  getInitialState: function() {
    return { deals: [] };
  },
  componentDidMount: function() {
    this.loadDealsFromServer();
  },
  loadDealsFromServer: function() {
    var newDeals = [];

    chrome.runtime.sendMessage({ action: "findDeals", personId: this.props.person.id }, function(deals) {
      newDeals = deals;
    });

    this.setState({ deals: newDeals });
  },
  render: function() {
    var dealNodes = this.state.deals.map(function(deal, index) {
      return (
        <Deal deal={deal} key={index} />
      );
    });
    return (
      <div className="deals">
        <table>
          <thead>
            <tr>
              <td>Name</td>
              <td>Amount</td>
              <td>Stage</td>
              <td>Probability</td>
              <td>Status</td>
              <td>Exp. Close</td>
            </tr>
          </thead>
          <tbody>
            {dealNodes}
          </tbody>
        </table>
      </div>
    );
  }
});

Однако, если я добавлю debugger, как показано ниже, newDeals заполняется, а затем, как только я продолжу, я вижу данные:

  loadDealsFromServer: function() {
    var newDeals = [];

    chrome.runtime.sendMessage({ action: "findDeals", personId: this.props.person.id }, function(deals) {
      newDeals = deals;
    });
    debugger
    this.setState({ deals: newDeals });
  },

Это список вызовов:

var Gmail = React.createClass({
  render: function() {
    return (
      <div className="main">
        <div className="panel">
          <DealsList person={this.props.person} />
        </div>
      </div>
    );
  }
});
4b9b3361

Ответ 1

Это потому, что ответ от chrome.runtime.sendMessage является асинхронным; здесь порядок операций:

var newDeals = [];

// (1) first chrome.runtime.sendMessage is called, and *registers a callback*
// so that when the data comes back *in the future*
// the function will be called
chrome.runtime.sendMessage({...}, function(deals) {
  // (3) sometime in the future, this function runs,
  // but it too late
  newDeals = deals;
});

// (2) this is called immediately, `newDeals` is an empty array
this.setState({ deals: newDeals });

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

Чтобы исправить, вы хотите выполнить вызов setState после того, как данные вернутся из расширения Chrome:

var newDeals = [];

// (1) first chrome.runtime.sendMessage is called, and *registers a callback*
// so that when the data comes back *in the future*
// the function will be called
chrome.runtime.sendMessage({...}, function(deals) {
  // (2) sometime in the future, this function runs
  newDeals = deals;

  // (3) now you can call `setState` with the data
  this.setState({ deals: newDeals });
}.bind(this));

Ответ 2

Я хотел бы добавить к этому чрезвычайно простое, но так легко сделанное сообщение:

this.state.something = 'changed';

... и затем не понимая, почему это не рендеринг и Google и не идет на эту страницу, только чтобы понять, что вы должны были написать:

this.setState({something: 'changed'});

Реагирует только на повторную визуализацию, если вы используете setState для обновления состояния.

Ответ 3

Еще одна ох-простая ошибка, которая была источником проблемы для меня: Id написал собственный метод shouldComponentUpdate, который не проверял добавленный новый идентификатор изменения состояния.