Компонент 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>
);
}
});
Ответы
Ответ 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
, который не проверял добавленный новый идентификатор изменения состояния.