从组件中反应增量状态

时间:2015-03-11 21:42:35

标签: reactjs setstate

我正在尝试创建一个类似于此处的反应示例的过滤表:Thinking in React。我想要添加的是从总项目集中显示的项目数量。我的想法是将状态变量'numShowing'保留在顶级组件“Resources”中。我还在这个组件中创建了一个函数,使用setState()递增'numShowing'。然后,我将该函数传递给组件链,并在安装感兴趣的组件时调用它。这是一些伪代码(我删除了不必要的东西和对过滤组件的引用):

组件层次结构是:资源 - > ResourcesTable - > ResourcesTableEntry。

var Resources = React.createClass({
  getInitialState: function() {
    return {
      numShowing: 0
    };
  },
  incrementShowing: function() {
    console.log('increment from: ' + this.state.numShowing);
    this.setState({numShowing: this.state.numShowing + 1});
  },
  render: function() {
      <div>
        <ResourcesTable resources={this.state.resources} incrementShowing={this.incrementShowing} />
      </div>
    );
  }
});

var ResourcesTable = React.createClass({
  createEntry: function(resource) {
      if (/* filtered out */) {
        return;
      } else {
        return(<ResourcesTableEntry key={resource.id} resource={resource} incrementShowing={this.props.incrementShowing} />);
      }
  },
  render: function() {
    return (
      <table>
          <tbody>
            { this.props.resources.map(this.createEntry) }
          </tbody>
      </table>
    );
  }
});

var ResourcesTableEntry = React.createClass({
  componentDidMount: function() {
    this.props.incrementShowing();
  },
  render: function() {
    return (
      <tr>
        /* output props here */
      </tr>
    );
  }
});

我还尝试从ResourcesTable.createEntry函数递增。在这两种情况下,numShowing只被设置为1.我认为这是因为setState是异步的或非原子的,所以当每次调用incrementShowing()时,numShowing的当前状态为0(控制台输出验证函数)被称为正确的次数)。那么这样做的“正确”方法是什么?

1 个答案:

答案 0 :(得分:0)

这里的问题是你不想在渲染方法中更新状态,因为它是反模式。可以通过将过滤移动到将拥有numShowing的组件(即Resources)来解决该问题。这可能会消除对ResourceTable组件的需求。

var Resources = React.createClass({
  render: function() {
    numShowing = 0;
    filteredResources = this.state.resources.map(function(resource){
      if (/* filtered out */) {
        return;
      }
      numShowing++; 
      return(<ResourcesTableEntry key={resource.id} resource={resource} />);
    }.bind(this));
    return(
      <div>
        <span> Number of results: {numShowing} </span>
        {filteredResources}
      </div>
    );
  }
});