React 组件不会在状态更改时重新渲染 [英] React component not re-rendering on state change

查看:65
本文介绍了React 组件不会在状态更改时重新渲染的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 React 类,它将通过 API 获取内容.我已经确认数据会返回,但不会重新渲染:

var DealsList = React.createClass({getInitialState: 函数() {返回{交易:[]};},componentDidMount:函数(){this.loadDealsFromServer();},loadDealsFromServer: function() {var newDeals = [];chrome.runtime.sendMessage({ action: "findDeals", personId: this.props.person.id }, function(deals) {新交易 = 交易;});this.setState({ Deals: newDeals });},渲染:函数(){var dealNodes = this.state.deals.map(function(deal, index) {返回 (<Deal deal={deal} key={index}/>);});返回 (<div className="deals"><表格><头><tr><td>姓名</td><td>金额</td><td>阶段</td><td>概率</td><td>状态</td><td>Exp.关闭</tr></thead>{交易节点}</tbody>

);}});

但是,如果我添加一个像下面这样的 debuggernewDeals 被填充,然后一旦我继续,我就会看到数据:

 loadDealsFromServer: function() {var newDeals = [];chrome.runtime.sendMessage({ action: "findDeals", personId: this.props.person.id }, function(deals) {新交易 = 交易;});调试器this.setState({ Deals: newDeals });},

这就是所谓的交易清单:

var Gmail = React.createClass({渲染:函数(){返回 (<div className="main"><div className="面板"><DealsList person={this.props.person}/>

);}});

解决方案

那是因为 chrome.runtime.sendMessage 的响应是异步的;以下是操作顺序:

var newDeals = [];//(1) 首先调用chrome.runtime.sendMessage,并*注册一个回调*//这样当数据回来时*在未来*//函数将被调用chrome.runtime.sendMessage({...}, function(deals) {//(3) 在未来的某个时候,这个函数会运行,//但为时已晚新交易 = 交易;});//(2) this 被立即调用,`newDeals` 是一个空数组this.setState({ Deals: newDeals });

当你用调试器暂停脚本时,你给了调用回调的扩展时间;到您继续时,数据已经到达并且似乎可以正常工作.

要解决此问题,您希望在数据从 Chrome 扩展程序返回后执行 setState 调用:

var newDeals = [];//(1) 首先调用chrome.runtime.sendMessage,并*注册一个回调*//这样当数据回来时*在未来*//函数将被调用chrome.runtime.sendMessage({...}, function(deals) {//(2) 在未来的某个时候,这个函数会运行新交易 = 交易;//(3) 现在你可以用数据调用`setState`this.setState({ Deals: newDeals });}.bind(this));//不要忘记绑定(this)(或使用箭头函数)

如果这对您不起作用,请查看此问题的其他答案,其中解释了您的组件可能无法更新的其他原因.

I have a React Class that's going to an API to get content. I've confirmed the data is coming back, but it's not re-rendering:

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>
    );
  }
});

However, if I add a debugger like below, newDeals are populated, and then once I continue, i see the data:

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

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

This is what's calling deals list:

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

解决方案

That's because the response from chrome.runtime.sendMessage is asynchronous; here's the order of operations:

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's too late
  newDeals = deals;
});

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

When you pause the script with the debugger, you're giving the extension time to call the callback; by the time you continue, the data has arrived and it appears to work.

To fix, you want to do the setState call after the data comes back from the Chrome extension:

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)); // Don't forget to bind(this) (or use an arrow function)

[Edit]

If this doesn't work for you, check out the other answers on this question, which explain other reasons your component might not be updating.

这篇关于React 组件不会在状态更改时重新渲染的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆