教程

我们将构建一个简单但好用的评论框,一个类似于Disqus,LiveFyre或Facebook评论的实时评论基本版本。

我们将提供:

  • 展示所有评论的视图
  • 提交评论的表单
  • 为你提供服务的自定义后端
  • Hooks for you to provide a custom backend

将要实现的简单功能

  • 开放评论:评论在保存到服务器之前会出现在评论列表中,所以会感觉速度很快。
  • 实时更新:其他用户的评论将会被实时更新到评论列表中。
  • 支持MakeDown:用户可以使用MakeDown编辑文本

想要跳过这一切,只看源码?

一切都在Github上

运行服务器

为了开始教程,我们需要一个运行的服务器。这个服务器只会为我们提供用于获取和保存数据的API。为了让这一切更容易,我们已经通过一些脚本语言创建了我们需要的一个简单的服务器,您可以[查看源代码]或者[下载一个压缩文件],里面包含开成教程的一切代码。

为了简单起见,我们将在服务器上使用一个JSON文件作为模拟数据库。你不会在工作中用到这一点(以JSON作为数据库),但是他能很容易的模拟一个API让你使用。一旦你启动服务器,它将为我们的静态页面提供API。

入门

在本教程中,我们会尽量让一切变得容易。上面提到的服务器软件包包含了一个HTML文件,我们将要在这个文件中进行我们的工作。用你喜欢的编辑器打开public/index.html文件。它应该是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>React Tutorial</title>
<script src="https://npmcdn.com/react@15.3.1/dist/react.js"></script>
<script src="https://npmcdn.com/react-dom@15.3.1/dist/react-dom.js"></script>
<script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script>
<script src="https://npmcdn.com/jquery@3.1.0/dist/jquery.min.js"></script>
<script src="https://npmcdn.com/remarkable@1.6.2/dist/remarkable.min.js"></script>
</head>
<body>
<div id="content"></div>
<script type="text/babel" src="scripts/example.js"></script>
<script type="text/babel">
// To get started with this tutorial running your own code, simply remove
// the script tag loading scripts/example.js and start writing code here.
</script>
</body>
</html>

对于本教程的其余部分,我们将在这个脚本标签来写我们的JsvaScript代码。我们没有使用任何先进的实时重载,所以你需要在保存后刷新浏览器才能看到更新。打开浏览器后地址栏输入http://localhost:3000(启动服务后)。当你第一次加载这个页面是看不到任何变化的,之后你将会看到我们构建结束后的效果。当你准好了要开始工作的时候,只要删除前面的<script>标签,然后就可以继续了。

注意

我们这里引入了jQuery,因为我们希望能够简化我们调用AJAX的代码,但它并不是React运行必须的。

你的第一个组件

React通过可组合的组件进行模块化的。对于我们评论框的列子,组成结构如下

1
2
3
4
- CommentBox
- CommentList
- Comment
- CommentForm

让我们创建CommentBox组件,它仅仅是一个简单的<div>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// tutorial1.js
var CommentBox = React.createClass({
render: function() {
return (
<div className="commentBox">
Hello, world! I am a CommentBox.
</div>
);
}
});
ReactDOM.render(
<CommentBox />,
document.getElementById('content')
);

需要注意的是HTML原生的元素名称以小写字母开头,而自定义的React组件标签以大写字母开头。

JSX语法

你会注意到的第一件事是在你的JavaScript中有XML的语法。我们有一个简单的预编译器会将这样的语法糖编译成普通的JavaScript:(这段代码展示是如何编译JSX的)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// tutorial1-raw.js
var CommentBox = React.createClass({displayName: 'CommentBox',
render: function() {
return (
React.createElement('div', {className: "commentBox"},
"Hello, world! I am a CommentBox."
)
);
}
});
ReactDOM.render(
React.createElement(CommentBox, null),
document.getElementById('content')
);

它的使用是可选的,但是我们发现比起普通JavaScript,使用JSX语法会更简单。了解更多关于JSX语法文章

这是怎么回事

我们通过JavaScript对象的一些方法React.createClass()创建一个新的React组件。最重要的,会通过render方法将React组件返回到HTML中渲染。

<div>不是实际的DOM节点;they are instantiations of React components.他们是React的实例组件。You can think of these as markers or !pieces! of data that React knows how to handle.你可以认为这是一种标记,React知道如何处理的数据。我们生成的不是HTML字符串,所以是可以防止XSS攻击的。

你不用返回基本的HTML。You can return a tree of components that you (or someone else) built.你可以返回你(或者其他人)构建的组件。This is what makes React composable : a key tenet of maintainable frontends.这就是为什么React可以组件化,一种方便维护的前端的关键原则。ReactDOM.render()方法第二个参数,实例根组件,启动框架,同时将组件注入原生DOM元素中。

ReactDOM模块暴露出特定的DOM相关的方法, while has the core tools shared by React on different platforms (e.g., React Native).同时React拥有不同的核心工具 || React对于不同的平台(例如:[ReactNative]),React共享同样的核心工具。

It is important that remain at the bottom of the script for this tutorial. should only be called after the composite components have been defined.很重要的一点,ReactDOM.render要放在script中的底部。ReactDOM.render方法必须在确定组件组合完毕后才能调用。

撰写组件

Let’s build skeletons for and which will, again, be simple s.让我们再次通过简单的<div>来构建CommentListCommentForm的骨架。将这两个组件添加到您的文件中,保留CommentBox的声明和ReactDOM.render的调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 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组件中使用这些新组件:

1
2
3
4
5
6
7
8
9
10
11
12
// tutorial3.js
var CommentBox = React.createClass({
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList />
<CommentForm />
</div>
);
}
});

请注意,我们如何是将HTML标签和我们自己构建的组件一起使用的。HTML组件是常规的React组件,就像你平时使用的HTML一样,但是有一点不同。The JSX compiler will automatically rewrite HTML tags to expressions and leave everything else alone.JSX编译器会自动重写HTML标记,通过React.createElement(tagName)方法生成,并且是独一无二的。这是为了防止全局命名空间污染。

使用props

通过父组件传递来的数据将会影响我们创建的Comment组件。Data passed in from a parent component is available as a ‘property’ on the child component.从父组件传递的数据对于子组件是可用的财产?These ‘properties’ are accessed through .这些”特性”通过访问this.props。使用props,我们能够从CommentList读取数据,传递给Comment, and render some markup:并渲染一些makeup,样式?标记?

1
2
3
4
5
6
7
8
9
10
11
12
13
// tutorial4.js
var Comment = React.createClass({
render: function() {
return (
<div className="comment">
<h2 className="commentAuthor">
{this.props.author}
</h2>
{this.props.children}
</div>
);
}
});

By surrounding a JavaScript expression in braces inside JSX (as either an attribute or child), you can drop text or React components into the tree.

在JSX中,可以通过括号中的JavaScript表达式(作为一个标签,属性或者子元素),你可以将文本或React组件插入到DOM树。