从服务器获取数据
现在我们将硬编码进去的数据改成从服务器获得动态数据。我们将删去data prop并用URL的方式获取数据。
修改main.tsx如下:
/// <reference path="../typings/react/react-global.d.ts"/>
import CommentBox = require("./CommentBox");
ReactDOM.render(<CommentBox url="/api/comments" />,document.getElementById('content'));
这个组件同之前组件不同之处是它能够重新渲染它自己。组件在从服务器获得数据之前是没有数据的。注:这一步代码还不能工作。
重激活状态
到现在为止,基于组件的props,每个组件能渲染自己一次。props
是不可变的:它由父组件传入并且由父组件“拥有”。为了实现交互,我们引入了可变的state到组件中。this.state
对组件来说是私有的,并且可以通过调用 this.setState()
进行改变。当状态更新时,组件能自行重新渲染。
render() 方法作为this.props
和 this.state
函数的声明式方法。框架保证UI总是跟输入保持一致。修改 CommentBox.tsx 如下
/// <reference path="../typings/react/react-global.d.ts"/>
import CommentList = require("./CommentList");
import CommentForm = require("./CommentForm");
export =CommentBox;
class CommentBox extends React.Component<any,any> {
getInitialState() {
return { data: [] }
}
render() {
return (
<div className="commentBox">
<h1>评论</h1>
<CommentList data={this.state.data} />
<CommentForm />
</div>
);
}
}
getInitialState()在组件的生命周期开始时执行一次并设置好组件的初始状态。
更新状态
当组件一开始创建的时想,我们想从服务器GET一些JSON并更新状态反映新新的数据。我们现在使用jQuery来异步获取从服务器提供的数据。数据在你启动服务器的时候已经包含 了(基于comments.json文件),所以当获取数据后,this.state.data
会象这样:
[
{"author": "Pete Hunt","text": "This is one comment"},{"author": "Jordan Walke","text": "This is *another* comment"}
]
现在CommentBox.tsx如下添加componetDidMount:
/// <reference path="../typings/react/react-global.d.ts"/>
/// <reference path="../typings/jquery/jquery.d.ts"/>
import CommentList = require("./CommentList");
import CommentForm = require("./CommentForm");
export =CommentBox;
interface CommentBoxProps { }
interface CommentBoxState { data: any; }
class CommentBox extends React.Component<CommentBoxProps,CommentBoxState> {
public state: CommentBoxState;
constructor(props: CommentBoxProps) {
super(props);
this.state = { data: [] };
}
componentDidMount() {
$.ajax({
url: this.props.url,dataType: 'json',cache: false,success: function (data) {
this.setState({ data: data });
}.bind(this),error: function (xhr,status,err) {
console.error(this.props.url,err.toString());
}.bind(this)
});
}
render() {
return (
<div className="commentBox">
<h1>评论</h1>
<CommentList data={this.state.data} />
<CommentForm />
</div>
);
}
}
在这里,componentDidMount 是由React在一个组件第一次渲染之后自动调用的一个方法。动态更新的的关键是调用 this.setState()
。我们将老的评论数组换成了从来自服务器的新数据,并自动的更新。因为这样的反应,我们只要一个小的改更就能添加活动更新。你还可以通过WebSockets或其它技术轻松使用它们。下面我们对这个进行更改:
/// <reference path="../typings/react/react-global.d.ts"/> /// <reference path="../typings/jquery/jquery.d.ts"/>
import CommentList = require("./CommentList");
import CommentForm = require("./CommentForm");
export =CommentBox;
interface CommentBoxProps
{
url: string;
pollInterval: number;
}
interface CommentBoxState { data: any; }
class CommentBox extends React.Component<CommentBoxProps,CommentBoxState> {
public state: CommentBoxState;
constructor(props: CommentBoxProps) {
super(props);
this.state = { data: [] };
}
loadCommentsFromServer() {
$.ajax({
url: this.props.url,dataType: 'json',cache: false,success: function (data) {
this.setState({ data: data });
}.bind(this),error: function (xhr,err) {
console.error(this.props.url,err.toString());
}.bind(this)
});
}
componentDidMount() {
this.loadCommentsFromServer();
//setInterval(this.loadCommentsFromServer,this.props.pollInterval);
//setInterval(() => this.loadCommentsFromServer,this.props.pollInterval); setInterval(() => this.loadCommentsFromServer(),this.props.pollInterval); } render() { return ( <div className="commentBox"> <h1>评论</h1> <CommentList data={this.state.data} /> <CommentForm /> </div> ); } }
CommentBox.tsx 中的修改是将AJAX的调用放到了一个单独的方法中。当组件第一次加载后每隔2秒钟更新数据。在这段修改的代码里我特别标注了两种错误的写法。注释掉的写法会导至不能按2秒更新数据。详细的解释可以参考:
参考stackoverflow中的一个问答
我们对main.tsx也进行修改:
/// <reference path="../typings/react/react-global.d.ts"/>
import CommentBox = require("./CommentBox");
ReactDOM.render(<CommentBox url="/api/comments" pollInterval={2000} />,document.getElementById('content'));