从this.state动态渲染行

时间:2017-02-22 20:44:02

标签: reactjs

对于ReactJS来说,我是绿色的,但它是我正在努力的项目的一部分,我试图了解如何正确改变一个组件状态:

我有一个Table组件,它在ES6中声明为:

class EmailStatisticTable extends React.Component {
    constructor (props) {
        super(props);
        this.state = {
            event_id: props.event_id,
            statistics: [],
            rows: []
        }
    }

    componentDidMount () {
        var self = this;
        $.getJSON('/events/' + this.state.event_id + '/emails/stats', function(resp){
            self.state.statistics = resp;
            self.state.statistics.forEach(function(statistic) {
                self.state.rows.push(<EmailStatisticRow statistic={statistic}/>);
            });
        });
        console.log(self.state.rows);
    }

    render () {
        return (
            <table className="table table-striped table-hover">
                <thead>
                    <tr>
                        <th> Recipient Type </th>
                        <th></th>
                    </tr>
                </thead>
                <tbody>{this.state.rows}</tbody>
            </table>
        )
    }
}

这里的想法是在this.state.rows更改时动态呈现行。我可以看到self.state.rows方法中的componentDidMount正确创建了EmailStatisticRow组件数组。其声明如下:

class EmailStatisticRow extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            statistic : props.statistic
        }
    }
    render () {
        return (
            <tr>
                <td>{this.state.statistic.record_type}</td>
                <td>{this.state.statistic.count}</td>
            </tr>
        )
    }
}

但是,在通过$.getJSON()从服务器发回数据后,行永远不会添加到DOM中。

我认为我的问题可能是对state管理层及其在ReactJS中的可变性/不变性的基本误解。

有人能说清楚这个话题吗?

感谢。

2 个答案:

答案 0 :(得分:2)

您应该通过setState()方法而不是直接设置状态。

所以替换:

self.state.statistics = resp;
            self.state.statistics.forEach(function(statistic) {
                self.state.rows.push(<EmailStatisticRow statistic={statistic}/>);
            });

使用

this.setState({
  statistics: resp
})

然后在渲染函数中替换

而不是分配行
<tbody>{this.state.rows}</tbody>

<tbody>{this.state.statistics.map(function(row) {
  return <EmailStatisticRow statistic={row}/>
})}</tbody>

编辑:进一步解释 - setState将触发渲染,所有统计行将映射到EmailStatisticRow组件。

答案 1 :(得分:1)

在React you should not mutate state中直接像这样:

self.state.rows.push(<EmailStatisticRow statistic={statistic}/>);

相反,请使用setState()

self.setState({rows: newRows});

它也是not advised to store rendered elements in state<EmailStatisticRow>),只需将statistics数据存储在州:

self.setState({statistics: resp});

并在render函数中呈现列表,例如使用map()

render () {
    return (
        <table className="table table-striped table-hover">
            <thead>
                <tr>
                    <th> Recipient Type </th>
                    <th></th>
                </tr>
            </thead>
            <tbody>
              { this.state.statistics.map(statistic => <EmailStatisticRow statistic={statistic}/>) }
          </tbody>
        </table>
    )
}

使用setState()会导致render()被调用,渲染应始终根据道具和状态为您提供完整的结果。这是React的基本渲染模式,使其具有可预测性。