用TypeScipt和AMD模块化理念实现React官方教程(五)提交和更新数据
2016-02-21 10:35
537 查看
添加新的评论
现在开始创建表单,我们的CommentForm组件会需要用户填写他们的姓名和评论内容并发送一个请求到服务器保存评论。
修改CommentForm.tsx 如下:
/// <reference path="../typings/react/react-global.d.ts"/> export =CommentForm; class CommentForm extends React.Component<any, any> { render() { return ( <form className="commentForm"> <input type="text" placeholder="Your name" /> <input type="text" placeholder="Say something..." /> <input type="submit" value="Post" /> </form> ); } }
控制组件
使用传统DOM,渲染input元素并由浏览器管理状态(它渲染的值)。因此,实际DOM的状态会跟组件的状态不同。视图的状态同组件不同是不理想的。在React中,组件总是代表着视图的状态,不仅仅在初始化的时候。
因此,我们会使用
this.state在用户键入时保存用户的输入。我们给初始
state定义了两个属性
author和
text并设置成空字符串。在我们的
<input>元素,我们设置
valueprop 反应组件的
state并附上
onChange处理它们。 这些
<input>元素带有
value设置的我们叫它们为控制组件。
/// <reference path="../typings/react/react-global.d.ts"/> export =CommentForm; interface CommentFormState { author: string; text: string; } class CommentForm extends React.Component<any, CommentFormState> { public state: CommentFormState; constructor(props) { super(props); this.state = { author: '', text: '' }; } handleAuthorChange = (e) => { this.setState({ author: e.target.value, text: this.state.text }); } handleTextChange = (e) => { this.setState({ author: this.state.author, text: e.target.value }); } render() { return ( <form className="commentForm"> <input type="text" placeholder="Your name" value={this.state.author} onChange={this.handleAuthorChange} /> <input type="text" placeholder="Say something..ok." value={this.state.text} onChange={this.handleTextChange} /> <input type="submit" value="Post" /> </form> ); } }
请特别注意事件处理程序跟官方教程的不同之处。
从程序中可以看出,为了使state和组件保持一致,使用了onChange。
事件
React使用驼峰命名规则给组件绑定事件处理。我们将onChange绑定到两个
<input>元素。现在,当用户输入文本时,绑定的处理函数触发回调,组件的
state将会更改。随后,input元素的渲染值会更新反应当前组件的状态。
提交表单
现在让表单进行互动,当用户提交表单后,我们将清除它,提交一个请求到服务器,并刷新评论列表。开始,让我们侦听表单提交事件并清除它。/// <reference path="../typings/react/react-global.d.ts"/> export =CommentForm; interface CommentFormState { author: string; text: string; } class CommentForm extends React.Component<any, CommentFormState> { public state: CommentFormState; constructor(props) { super(props); this.state = { author: '', text: '' }; } handleAuthorChange = (e) => { this.setState({ author: e.target.value, text: this.state.text }); } handleTextChange = (e) => { this.setState({ author: this.state.author, text: e.target.value }); } handleSubmit=(e)=>{ e.preventDefault(); var author = this.state.author.trim(); var text = this.state.text.trim(); if (!text || !author) { return; } // TODO: send request to the server this.setState({ author: '', text: '' }); } render() { return ( <form className="commentForm" onSubmit={this.handleSubmit} > <input type="text" placeholder="Your name" value={this.state.author} onChange={this.handleAuthorChange} /> <input type="text" placeholder="Say something..ok." value={this.state.text} onChange={this.handleTextChange} /> <input type="submit" value="Post" /> </form> ); } }
我们绑定 onSubmit 来处理表单,当表单输入有效后提交并请除清单字段。请用
preventDefault()是为了阻止浏览器缺省的提交表单动作。
用回调函数作为props
当用户提交一个评论时,我们需要刷新评论列表包含新的这个评论。在CommentBox中放置 所有的逻辑是合适的,因为
CommentBox包含了代表当前评论列表的状态。
我们需要将数据从子组件传回到父组件中。我们在父组件的 render 方法中通过传递一个新的回调函数(
handleCommentSubmit)到子组件。绑定到子组件的
onCommentSubmit事件。无论什么时候触发,回调函数都会被调用。
/// <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, status, err) { console.error(this.props.url, status, err.toString()); }.bind(this) }); } handleCommentSubmit = (comment) => { //Todo:提交到服务器并刷新列表 } 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 onCommentSubmit={this.handleCommentSubmit} /> </div> ); } }
当用户提交表单时,让我们从
CommentForm中调用回调函数。
/// <reference path="../typings/react/react-global.d.ts"/> export =CommentForm; interface CommentFormState { author: string; text: string; } class CommentForm extends React.Component<any, CommentFormState> { public state: CommentFormState; constructor(props) { super(props); this.state = { author: '', text: '' }; } handleAuthorChange = (e) => { this.setState({ author: e.target.value, text: this.state.text }); } handleTextChange = (e) => { this.setState({ author: this.state.author, text: e.target.value }); } handleSubmit=(e)=>{ e.preventDefault(); var author = this.state.author.trim(); var text = this.state.text.trim(); if (!text || !author) { return; } this.props.onCommentSubmit({ author: author, text: text }); this.setState({ author: '', text: '' }); } render() { return ( <form className="commentForm" onSubmit={this.handleSubmit} > <input type="text" placeholder="Your name" value={this.state.author} onChange={this.handleAuthorChange} /> <input type="text" placeholder="Say something..ok." value={this.state.text} onChange={this.handleTextChange} /> <input type="submit" value="Post" /> </form> ); } }
现在回调函数已经就绪,我们现在要做的只是提交到服务器并刷新列表:
优化:提前更新
我们的应用现在已经功能完备了,但是新添加的评论需要等待对服务器的请求完成后才会出现在列表中, 这样感觉会慢一点。我们可以提前将这条评论放到列表中让应用感觉更快。/// <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, status, err) { console.error(this.props.url, status, err.toString()); }.bind(this) }); } handleCommentSubmit = (comment) => { var comments = this.state.data; // Optimistically set an id on the new comment. It will be replaced by an // id generated by the server. In a production application you would likely // not use Date.now() for this and would have a more robust system in place. comment.id = Date.now(); var newComments = comments.concat([comment]); this.setState({ data: newComments }); $.ajax({ url: this.props.url, dataType: 'json', type: 'POST', data: comment, success: function (data) { this.setState({ data: data }); }.bind(this), error: function (xhr, status, err) { this.setState({ data: comments }); console.error(this.props.url, status, 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 onCommentSubmit={this.handleCommentSubmit} /> </div> ); } }
OK,教程到此结束,因为不是专业写作,肯定有很多不足之处,欢迎各种拍砖和讨论。等时间充裕时我再整理一下整个教程,有可能的话在GitHub上把所有源代码上传以便大家直接开箱使用。
相关文章推荐
- 比较react和flex的设计哲学
- react-native 入门资源合集
- 用TypeScipt和AMD模块化理念实现React官方教程(四)获取数据
- react-native启动异常,react-deep-force-update/.babelrc
- react-native启动异常,react-deep-force-update/.babelrc
- react-active init XXX 没反应
- 用TypeScipt和AMD模块化理念实现React官方教程(三)静态页面
- ReactiveCocoa简介6,添加附加操作(Adding side-effects)
- ReactiveCocoa简介五:用信号封装异步API
- ReactiveCocoa简介四,Button的点击事件的实现
- ReactiveCocoa简介四,聚合信号
- ReactiveCocoa简介三,根据输入框的条件,改变输入框背景颜色
- ReactiveCocoa简介二,值的传递
- ReactiveCocoa简介一,什么是信号量和基本操作
- react native 安装指南
- React-Native OpenGL体验二
- React Native For Android On Windows
- ReactJS初步学习
- React Native-11.React Native TabBarIOS TabBarIOS.Item组件详解
- React.js组件的生命周期