React组件不会在状态更改时重新呈现

时间:2014-09-19 15:25:40

标签: javascript reactjs

我有一个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>
    );
  }
});

9 个答案:

答案 0 :(得分:51)

我想补充一点非常简单,但是很容易犯错误的写作:

this.state.something = 'changed';

...然后不理解为什么它没有渲染和谷歌搜索并进入这个页面,只是意识到你应该写的:

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

如果使用setState更新状态,则React仅触发重新渲染。

答案 1 :(得分:13)

那是因为来自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's too late
  newDeals = deals;
});

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

当您使用调试器暂停脚本时,您将给予延长时间来调用回调;当你继续时,数据已经到达并且似乎有效。

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

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)

[编辑]

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

答案 2 :(得分:10)

另一个很容易犯的错误,这是我的问题的根源:我编写了自己的shouldComponentUpdate方法,它没有检查我添加的新状态更改。

答案 3 :(得分:7)

我的情况有点不同。而且我认为很多像我这样的新手都会被难住 - 所以在这里分享。

我的状态变量是一个由 useState 管理的 JSON 对象数组,如下所示:

const [toCompare, setToCompare] = useState([]);

但是,当使用 setToCompare 更新 toCompare 时,如下面的函数所示 - 不会触发重新渲染。并将其移动到不同的组件也不起作用。只有当某些其他事件会触发重新渲染时 - 才会显示更新的列表。

const addUniversityToCompare = async(chiptoadd) =>
  {
      var currentToCompare = toCompare;
      currentToCompare.push(chiptoadd);
      setToCompare(currentToCompare);
  }

这就是我的解决方案。基本上 - 分配数组是复制引用 - 并且反应不会将其视为更改 - 因为数组的引用没有被更改 - 只有其中的内容。所以在下面的代码中 - 只是使用切片复制了数组 - 没有任何更改 - 并在 mods 之后将其分配回来。工作得很好。

const addUniversityToCompare = async (chiptoadd) => {
    var currentToCompare = toCompare.slice();
    currentToCompare.push(chiptoadd);
    setToCompare(currentToCompare);
}

希望它能帮助像我这样的人。任何人,如果您觉得我错了,请告诉我 - 或者有其他方法。

提前致谢。

答案 4 :(得分:4)

在我的情况下,我正确地调用了this.setState({}),但是我的功能并没有受到约束,所以它无效。将.bind(this)添加到函数调用或在构造函数中执行this.foo = this.foo.bind(this)修复它。

答案 5 :(得分:1)

我在React-Native中遇到了同样的问题,其中API响应&amp;拒绝不更新状态

apiCall().then(function(resp) { this.setState({data: resp}) // wasn't updating }

我通过使用箭头功能

更改function来解决问题
apiCall().then((resp) => {
    this.setState({data: resp}) // rendering the view as expected
}

对我来说,这是一个具有约束力的问题。使用箭头函数解决了它,因为箭头函数没有创建它自己的this,它总是受到它来自的外部环境的限制

答案 6 :(得分:1)

我的问题是,当我应该使用“ React.Component”时,我正在使用“ React.PureComponent”。

答案 7 :(得分:1)

我正在更新并返回传递给我的减速器的相同对象。我通过在像这样返回状态对象之前制作元素的副本来解决这个问题。

Object.assign({}, state)

答案 8 :(得分:0)

研究了很多答案(大多数答案都适合他们的情况),但都没有解决我的问题后,我意识到我的情况有所不同:

在我的怪异场景中,我的组件正在状态内渲染,因此无法更新。 下面是一个简单的示例:

/mnt/

将代码重构为使其处于可以正常工作的状态:)