翻译至官方文档《Tutorial》http://facebook.github.io/react/docs/tutorial.html

转载请注明出处:http://blog.csdn.net/adousen

推荐阅读 React|RakNet 博客:http://blog.csdn.net/rsspub/article/category/1435601

教程演示样例代码,Web程序框架採用的是全栈python web框架Uliweb

Uliweb  https://github.com/adousen/reactjs_uliweb_example

在新手教程里,我们会创建一个简单却有用的评论盒子来作为我们的样例,你能够把它放进一个博客什么的。

它实际上就是Disqus、LiveFyre、Facebook等实时评论的基础实现。

我们要实现的功能有:

  • 浏览全部的评论
  • 提交一个评论的表单
  • 为你自己定义的后端提供一个钩子

此外,另一些优化特性:

  • 优化评论:在评论保存到server前,就在列表中将其显示。这样会感觉更快。
  • 实时更新:当其他用户做出评论后,评论列表就能够得到实时的更新。

  • 支持Markdown格式:用户能够用Markdown格式书写内容。

第一步

在教程中。我们直接使用的是CDN上的Javascript框架文件。

以下,打开随意你喜欢的编辑器。创建一个新的HTML文档:

<!-- template.html -->
<html>
<head>
<title>Hello React</title>
<script src="http://fb.me/react-0.12.0.js"></script>
<script src="http://fb.me/JSXTransformer-0.12.0.js"></script>
<script src="http://code.jquery.com/jquery-1.10.0.min.js"></script>
</head>
<body>
<div id="content"></div>
<script type="text/jsx">
// Your code here
</script>
</body>
</html>

此后的教程中。我们都将在这里的script标签内编写JavaScript代码。

注意

此处我们将jQuery包括了进来,但目的仅仅是为了方便编写ajax调用。

但这不是在React中所必须做。

你的第一个组件

React全部的一切都是关于模块化、复合化的组件。就我们的评论功能来说。我们将依照以下的组件结构来实现:

- CommentBox
- CommentList
- Comment
- CommentForm

我们先来创建一个CommentBox组件,它一開始仅仅是一个简单的<div>:

// tutorial1.js
var CommentBox = React.createClass({
render: function() {
return (
<div className="commentBox">
Hello, world! I am a CommentBox.
</div>
);
}
});
React.render(
<CommentBox />,
document.getElementById('content')
);

JSX 语法

首先。你注意到的是Javascript代码中的XML化语法。

我们实际上能够使用一个预编译器来将此语法糖转换为纯Javascript:

// tutorial1-raw.js
var CommentBox = React.createClass({displayName: 'CommentBox',
render: function() {
return (
React.createElement('div', {className: "commentBox"},
"Hello, world! I am a CommentBox."
)
);
}
});
React.render(
React.createElement(CommentBox, null),
document.getElementById('content')
);

这是一种可选的方式,但实际上能够发现JSX语法要比单纯的Javascript语法要简单。

了解很多其它有关 JSX 语法的内容。

接下来做什么

以下我们要创建一个新的React组件,採取的方式是向 React.createClass() 传递一个Javascript对象。为组件加入一些方法。当中最重要的一个方法是 render,它会返回一个React组件树。并终于被渲染成HTML。

div 标签并非真正的DOM节点,它们仅仅是React div组件的实例。你能够把它想象成能由React识别并处理的一些标记或一段数据。

React是安全的。我们并不生成HTML字符串。所以默认是XSS保护。

你能够返回一个由你或别人创建的组件树,而不一定要返回主要的HTML。正因如此,React组件能够组合使用的:这是可维护前端的宗旨。

React.render() 初始化了一个根节点组件,然后启动框架,并将标记注入到一个原生DOM元素中。这个DOM元素由第二个參数指定。

组建组件

接着我们创建 CommentList 和 CommentForm 基本骨架,它们相同也是 div。注意,这段代码要放在CommentBox 代码的前面。

// tutorial2.js
var CommentList = React.createClass({
render: function() {
return (
<div className="commentList">
Hello, world! I am a CommentList.
</div>
);
}
});
 
var CommentForm = React.createClass({
render: function() {
return (
<div className="commentForm">
Hello, world! I am a CommentForm.
</div>
);
}
});

下一步。更新 CommentBox 组件的代码。使用新定义的两个朋友:

// tutorial3.js
var CommentBox = React.createClass({
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList />
<CommentForm />
</div>
);
}
});

注意我们是怎样混合使用HTML标签和自建组件的。

HTML组件是规范的React组件。与自己定义的组件类似,仅仅是有一个区别:JSX编译器会自己主动将HTML标签重写为 React.createElement(tagName) 。而且无论其他的事情。

这是了避免对全局命名空间的污染。

组件属性

我们将创建一个第三方组件 Comment,它负责接收评论者的名字和评论的内容。对于每一个单独的评论。我们都能够重用这个组件的代码。首先,我们向 CommentList 加入一些评论。

// tutorial4.js
var CommentList = React.createClass({
render: function() {
return (
<div className="commentList">
<Comment author="Pete Hunt">This is one comment</Comment>
<Comment author="Jordan Walke">This is *another* comment</Comment>
</div>
);
}
});

注意到,这里我们通过父组件 CommentList 向子组件 Comment 传递了一些数据。比方,我们在一个 Comment中,向其传递了Pete
Hunt
(通过属性)和一条评论(通过XML格式的子节点)。从父组件向子组件传递的数据被称为props(单词properties的缩写)。

使用props

接下来,我们就来创建这个Comment组件。使用porps我们能够读取从 CommentList 传递的数据,并渲染一些标记。

// tutorial5.js
var Comment = React.createClass({
render: function() {
return (
<div className="comment">
<h2 className="commentAuthor">
{this.props.author}
</h2>
{this.props.children}
</div>
);
}
});

在JSX中通过用括号括起来的JavaScript表达式,能够将文本或者React组件(能够是一个属性或子元素)放进组件树中。

this.props 和嵌套元素 this.props.children 中的keywordprops是传递给组件的命名属性。

加入 Markdowen语法支持

Markdown文本支持内联样式。比如。用星号围起的文本能够强调显示。

首先。我们须要向程序中加入第三方的 Showdown 库。这是一个支持Markdown并将其转换为原始HTML代码的JavaScript库。

我们须要向head中加入一段script标签(我们已经包括了一些React的库):

<!-- template.html -->
<head>
<title>Hello React</title>
<script src="http://fb.me/react-0.12.0.js"></script>
<script src="http://fb.me/JSXTransformer-0.12.0.js"></script>
<script src="http://code.jquery.com/jquery-1.10.0.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/showdown/0.3.1/showdown.min.js"></script>
</head>

下一步,我们将评论的文本做Markdown转换并输出:

// tutorial6.js
var converter = new Showdown.converter();
var Comment = React.createClass({
render: function() {
return (
<div className="comment">
<h2 className="commentAuthor">
{this.props.author}
</h2>
{converter.makeHtml(this.props.children.toString())}
</div>
);
}
});

此处,我们添加了对Showdown库的调用。为了将 this.props.children 从React包装了的文本转换成Showdown能够接受的原始字符串。我们显式地调用了 toString()

可是,这里有一个问题须要解决。我们最后渲染出来的评论内容在浏览器中看起来却是这种形式:"<p>This is <em>another</em> comment</p>"。

我们想要的是让这些标签都能被渲染为实际的HTML。

这样的处理方式是为了防止XSS攻击。

有一种方式能够跳过。可是框架会警告你不要使用这样的方式。

// tutorial7.js
var converter = new Showdown.converter();
var Comment = React.createClass({
render: function() {
var rawMarkup = converter.makeHtml(this.props.children.toString());
return (
<div className="comment">
<h2 className="commentAuthor">
{this.props.author}
</h2>
<span dangerouslySetInnerHTML={{__html: rawMarkup}} />
</div>
);
}
});

这个特殊的API的目的是让插入原生的HTML代码显得困难,可是为Showdown我们还是利用了这个后门。

记住:使用这个特征时。你必须确定Showdown是安全的。

连接数据模型

眼下为止,我们是直接在源码中插入评论。以下,我们将在评论列表中渲染一段JSON数据。终于,我们将从server端获取。可是如今,我们把它直接写在代码中:

// tutorial8.js
var data = [
{author: "Pete Hunt", text: "This is one comment"},
{author: "Jordan Walke", text: "This is *another* comment"}
];

我们须要以编写模块的方式将数据data加入进 CommentList.因此,我们改动 CommentBox 组件
以及 React.render() 调用的代码,将data通过props进行传递。

// tutorial9.js
var CommentBox = React.createClass({
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList data={this.props.data} />
<CommentForm />
</div>
);
}
});
 
React.render(
<CommentBox data={data} />,
document.getElementById('content')
);

如今,data已经被传递进了 CommentList,那么让我们来动态地呈现评论数据:

// tutorial10.js
var CommentList = React.createClass({
render: function() {
var commentNodes = this.props.data.map(function (comment) {
return (
<Comment author={comment.author}>
{comment.text}
</Comment>
);
});
return (
<div className="commentList">
{commentNodes}
</div>
);
}
});

就是这样!

从server读取

以下,我们用从server端读取的动态数据来替换硬性编码的数据。我们删除了 data 属性,改为採用 URL 来获取:

// tutorial11.js
React.render(
<CommentBox url="comments.json" />,
document.getElementById('content')
);

这个组件和之前的组件的不同之处在于它必须预先自行渲染。

在从server端获得请求应答之前,它没有可用的数据,而这些数据是组件呈现评论所必须的。

反应state

到如今为止,全部的组件都仅仅是依据自身的props进行一次性的渲染。props 是不可变的:它们是从父组件传递过来,而且为父组件全部。为了实现交互。我们为组件引入了可变的 state 。this.state属于组件的私有成员。而且能够通过调用 this.setState() 进行改动。当state更新之后。组件会马上对其自身进行又一次渲染。

实际上在React代码中。render() 方法被被声明为 this.props 和 this.state 的函数,并由框架保证了UI总是与输入保持一致。

当从server取得数据后,就能够对我们的评论数据进行改动。

首先,我们向 CommentBox 组件的state加入一个包括评论数据的数组data:

// tutorial12.js
var CommentBox = React.createClass({
getInitialState: function() {
return {data: []};
},
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList data={this.state.data} />
<CommentForm />
</div>
);
}
});

在组件的生命周期中,getInitialState() 仅仅运行一次。它负责对组件的state进行初始化。

更新state

在组件创建完成后,我们还想要从serverGET到JSON,从而更新state来反映最新的数据。

在实际的应用中。我们可能创建的是一个动态的应用。可是,在样例中为了简单。还是使用一个静态的JSON文件:

// tutorial13.json
[
{"author": "Pete Hunt", "text": "This is one comment"},
{"author": "Jordan Walke", "text": "This is *another* comment"}
]

我们打算使用jQuery对server进行异步的訪问。

注意: 因为这是一个AJAX应用,因此你须要在一个webserver上执行,而不能仍停留在文件系统。

最简单的方式是在应用的文件夹下执行python -m SimpleHTTPServer

// tutorial13.js
var CommentBox = React.createClass({
getInitialState: function() {
return {data: []};
},
componentDidMount: function() {
$.ajax({
url: this.props.url,
dataType: 'json',
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList data={this.state.data} />
<CommentForm />
</div>
);
}
});

这里的componentDidMount是一个在React组件渲染以后将被React调用的方法。动态更新的关键取决于 this.state的调用。在从server取得数据以后。我们就使用新数组替换评论组件的旧数据,而且让它动态地改变。这样的反应的方式。使得动态更新仅仅是做了小小的改变。

此处,我们使用的投票数据非常简单,你也能够非常easy使用WebSockets或其他技术来获得。

// tutorial14.js
var CommentBox = React.createClass({
loadCommentsFromServer: function() {
$.ajax({
url: this.props.url,
dataType: 'json',
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
getInitialState: function() {
return {data: []};
},
componentDidMount: function() {
this.loadCommentsFromServer();
setInterval(this.loadCommentsFromServer, this.props.pollInterval);
},
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList data={this.state.data} />
<CommentForm />
</div>
);
}
});
 
React.render(
<CommentBox url="comments.json" pollInterval={2000} />,
document.getElementById('content')

此处我们做的不过将AJAX调用放到一个独立的方法中,而且在组件第一次载入和此后每隔两秒调用一次。

能够尝试在浏览器中执行一下,而且手动改动 comments.json。能够看到,在两秒内变化就被呈现了出来。

加入新的评论

如今。是时候创建一个评论表单了。

我们的 CommentForm 组件须要向询问用户他们的名字和评论的内容。并将其发送给server进行保存。

// tutorial15.js
var CommentForm = React.createClass({
render: function() {
return (
<form className="commentForm">
<input type="text" placeholder="Your name" />
<input type="text" placeholder="Say something..." />
<input type="submit" value="Post" />
</form>
);
}
});

让我们来创建与表单的交互。

当用户点击submit提交以后,我们须要将表单清空。并将一个请求发送到server。然后更新评论列表。那么,首先我们须要监听表单的submit事件。并将其清空。

// tutorial16.js
var CommentForm = React.createClass({
handleSubmit: function(e) {
e.preventDefault();
var author = this.refs.author.getDOMNode().value.trim();
var text = this.refs.text.getDOMNode().value.trim();
if (!text || !author) {
return;
}
// TODO: send request to the server
this.refs.author.getDOMNode().value = '';
this.refs.text.getDOMNode().value = '';
return;
},
render: function() {
return (
<form className="commentForm" onSubmit={this.handleSubmit}>
<input type="text" placeholder="Your name" ref="author" />
<input type="text" placeholder="Say something..." ref="text" />
<input type="submit" value="Post" />
</form>
);
}
});

事件Events

React向组件加入的事件处理函数使用的是驼峰命名规则。

我们向表单加入了一个 onSumbit 的处理函数。它负责在输入数据合法的表单提交后,将表单的字段清空。

在事件处理中。调用 preventDefault 是为了阻止浏览器默认的与表单提交有关的行为。

Refs

我们使用 ref 属性向子组件分配了一个名字,而且通过 this.refs对组件进行引用。我们能够在一个组件上调用 getDOMNode 获取一个原生DOM元素。

在props中定义回调函数

当用户提交一条评论时,我们还须要对之前的评论列表进行更新。让新的评论显示进来。对于含有与呈现评论有关数据的state的CommentBox 来说,须要定义这种行为逻辑。

我们须要从子组件传送数据到它的父组件。我们在父组件的 render 方法中将一个新的回调函数(handleCommentSubmit)传递给子组件,并将其绑定在子组件的 onCommentSubmit 事件上。当事件被触发后。回调函数就会被运行。

// tutorial17.js
var CommentBox = React.createClass({
loadCommentsFromServer: function() {
$.ajax({
url: this.props.url,
dataType: 'json',
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: function(comment) {
// TODO: submit to the server and refresh the list
},
getInitialState: function() {
return {data: []};
},
componentDidMount: function() {
this.loadCommentsFromServer();
setInterval(this.loadCommentsFromServer, this.props.pollInterval);
},
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList data={this.state.data} />
<CommentForm onCommentSubmit={this.handleCommentSubmit} />
</div>
);
}
});

当用户提交表单的时候,我们就从 CommentForm 调用回调函数。

// tutorial18.js
var CommentForm = React.createClass({
handleSubmit: function(e) {
e.preventDefault();
var author = this.refs.author.getDOMNode().value.trim();
var text = this.refs.text.getDOMNode().value.trim();
if (!text || !author) {
return;
}
this.props.onCommentSubmit({author: author, text: text});
this.refs.author.getDOMNode().value = '';
this.refs.text.getDOMNode().value = '';
return;
},
render: function() {
return (
<form className="commentForm" onSubmit={this.handleSubmit}>
<input type="text" placeholder="Your name" ref="author" />
<input type="text" placeholder="Say something..." ref="text" />
<input type="submit" value="Post" />
</form>
);
}
});

如今。回调函数已经定义完成。

我们要做的就是提交新的评论到server,并刷新评论列表。

// tutorial19.js
var CommentBox = React.createClass({
loadCommentsFromServer: function() {
$.ajax({
url: this.props.url,
dataType: 'json',
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: function(comment) {
$.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) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
getInitialState: function() {
return {data: []};
},
componentDidMount: function() {
this.loadCommentsFromServer();
setInterval(this.loadCommentsFromServer, this.props.pollInterval);
},
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList data={this.state.data} />
<CommentForm onCommentSubmit={this.handleCommentSubmit} />
</div>
);
}
});

优化:优化更新

现状我们已经实现了这个应用的全部功能。

可是。在从server完毕请求之前,你必须等待评论在列表中出现。因此,会感觉有点慢。我们能够对它再做一点优化,让它感觉更快一点。

// tutorial20.js
var CommentBox = React.createClass({
loadCommentsFromServer: function() {
$.ajax({
url: this.props.url,
dataType: 'json',
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: function(comment) {
var comments = this.state.data;
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) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
getInitialState: function() {
return {data: []};
},
componentDidMount: function() {
this.loadCommentsFromServer();
setInterval(this.loadCommentsFromServer, this.props.pollInterval);
},
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList data={this.state.data} />
<CommentForm onCommentSubmit={this.handleCommentSubmit} />
</div>
);
}
});

祝贺你。

通过一些简单的步骤,你已成功创建了一个评论盒子。

你能够了解很多其它有关为什么使用React 或者深入的学习 API參考
祝你顺利。

React JS高速新手教程的更多相关文章

  1. C#游戏开发高速新手教程Unity5.5教程

    C#游戏开发高速新手教程Unity5.5教程 试读文档下载地址:http://pan.baidu.com/s/1slwBHoD C#是微软公布的高级程序设计语言.这门语言和C语言一样,已经成为了大学计 ...

  2. Arduino Yun高速新手教程(大学霸内部资料)

    Arduino Yun高速新手教程(大学霸内部资料) 本资料为国内第一本Arduino Yun教程.具体解说Arduino Yun的基本结构.开发环境.系统配置.并着力解说关键功能--Bridge.最 ...

  3. SVN高速新手教程

    因为做Zip和Rar解析的时候,找到了mucommander工具,可将其jar包导入项目里执行发现报:类型转换错误,org.apache.commons.logging.impl.Log4JLogge ...

  4. React JS快速入门教程

    翻译至官方文档<Tutorial>http://facebook.github.io/react/docs/tutorial.html 转载请注明出处:http://blog.csdn.n ...

  5. NetBeans工具学习之道:NetBeans IDE Java 高速新手教程

    欢迎使用 NetBeans IDE! 本教程通过指导您创建一个简单的 "Hello World" Java 控制台应用程序,简要介绍 NetBeans IDE 工作流.学习完本教程 ...

  6. Velocity高速新手教程

    变量 (1)变量的定义: #set($name = "hello")      说明:velocity中变量是弱类型的. 当使用#set 指令时,括在双引號中的字面字符串将解析和又 ...

  7. React JS和React-Native学习指南

    自己在学习React-Native过程中整理的一份学习指南,包含 教程.开源app和资源网站等,还在不断更新中.欢迎pull requests! React-Native学习指南本指南汇集React- ...

  8. React.js 新手教程

    正如你能从标题猜到的,这篇文章的目标是给那些有很少编程经验的读者的.比如,像我这样的人:因为迄今为止,我才探索了编程世界6个月.所以,这将是一篇新手村教程! 你只需要拥有对 HTML 和 CSS 的理 ...

  9. React.js 官网入门教程 分离文件 操作无法正常显示HelloWord

    对着React官网的教程练习操作,在做到分离文件练习时,按照官网步骤来却怎么也无法正常显示HelloWord. 经测试,html文件中内容改为: <!DOCTYPE html><ht ...

随机推荐

  1. C# WPF Datagrid的筛选

    public static void SearchResult(DataGrid dg,string condition) { #region string code = string.Empty; ...

  2. HTTP代理与SPDY协议(转)

    原文出处: fqrouter HTTP代理是最经典最常见的代理协议.其用途非常广泛,普遍见于公司内网环境,一般员工都需要给浏览器配置一个HTTP代理才能访问互联网.起初,HTTP代理也用来翻越“功夫网 ...

  3. Android源代码同步脚本(增加设置线程参数)

    #!/bin/sh #Filename: repo_sync.sh count= ret= ] do #输入参数1,用作同步的线程数 #如果什么参数都不输入,默认线程为4 #usage: ./repo ...

  4. 怎样配置nginx同一时候执行不同版本号的php-fpm

    在/usr/local/php/etc/php-fpm.conf里找到 listen = 127.0.0.1:9000 将port9000改动为9001 在对应的nginx配置里也做相同的port改动

  5. DIY.NETORM帧——技术储备(1)Attribute

    1.他是什么 ? 首先.我们当然Attribute它是一类,以下是一msdn文档对它的描写叙述:          公共语言执行时同意你加入类似keyword的描写叙述声明,叫做attributes, ...

  6. wpf 模拟3D效果(和手机浏览图片效果相似)(附源码)

    原文 wpf 模拟3D效果(和手机浏览图片效果相似)(附源码) pf的3D是一个很有意思的东西,类似于ps的效果,类似于电影动画的效果,因为动画的效果,(对于3D基础的摄像机,光源,之类不介绍,对于依 ...

  7. height:100%失败

    height显然,设置100% 为什么不能看到效果.非常多的时间不是很扎实的时间的基础上,,经常会遇到这样的问题,原因很简单的事实 首先,你必须确保 html{height:100%;} body{h ...

  8. 10令人惊叹的模型的影响HTML5应用程序及源代码

    HTML5已经越来越流行起来了.尤其是移动互联网的发展,更是带动了HTML5的迅猛发展,我们也是时候学习HTML5了,以防到时候落伍.今天给大家介绍10款效果惊艳的HTML5应用.方便大家学习,也将应 ...

  9. HBase系列文章汇总

    本文整理汇总了本博客自去年学习HBase以来写的全部关于HBase的相关内容.持续更新中,很多其它内容.敬请关注! 相关知识: 1.<布隆过滤器(Bloom Filter)> 2.< ...

  10. Cocos2d-x示例:单点触摸事件

    为了让大家掌握Cocos2d-x中的事件机制,以下我们以触摸事件为例.使用事件触发器实现单点触摸事件.该实比如图8-3所看到的,场景中有三个方块精灵,显示顺序如图8-3所看到的,拖拽它们能够移动它们. ...