。
```
Title
```
单一.css 和单一.js 的文件组织形式适用于大部分应用。但当你的应用规模接近Facebook 和Twitter 时,初始化加载这些脚本就会非常耗时,而且用户可能不需要一开始就用到所有功能。这时你可以建立一个脚本/ 资源加载器,使得代码可以按需加载。(这个方案将留给你思考。别忘了,有许多开源的解决方案可供选择。)在这种场景下,初始加载的单一.css 和.js 文件可以理解为一种引导文件,让用户可以在第一时间看到首屏内容。因此,在应用规模增长时,这种单一文件的模式依然有其用武之地。
你马上就会知道如何把独立的资源文件打包为bundle.js 和bundle.css 文件。但在此之前,你需要了解每个CSS/JS 文件的作用。
# 3、CSS
全局作用的样式文件/css/app.css 包含了整个应用的通用样式,如下所示:
```
html{
background: white;
font: 16px Arial;
}
```
除全局样式外,你还需要为每个组件定义具体样式。前面我们已经约定每个组件对应一个CSS 文件(和一个JavaScript 文件),放置在/css/components(和/js/source/components)。
现在我们来实现/css/components/Logo.css 文件:
```
.Logo{
background-image: url('../../images/react-logo.svg');
background-size: cover;
display: inline-block;
height: 50px;
vertical-align: middle;
width: 50px;
}
```
此处还遵循了另一个实用的小约定:在保持组件名称首字母大写的同时,还要给组件的顶层元素设置和该组件名相同的类名,在这里对应为className="Logo"。
# 4、JavaScript
应用的入口处是/js/source/app.js 脚本文件。入口文件是所有逻辑开始的地方,因此我们在该文件中这样编写:
```
React.render(
Welocome to The App!
,
document.getElementById("app")
)
```
最后,在/js/source/components/Logo.js 文件中,实现示例React 组件
的逻辑:
```
var Logo=React.createClass({
render:function () {
return
}
});
```
# 5、更现代化的JavaScript
直到目前,本书中的例子都只用到了一些简单的组件,而且出于方便起见,让React 和ReactDOM 暴露为全局变量。但当你的应用变得复杂,且组件数量越来越多的时候,你就需要使用更好的代码组织形式。这是因为暴露全局变量是有风险的(往往会导致命名冲突),一直依赖全局变量也并不安全。(试想把不同的JavaScript 打包起来时,内容不是放在单个bundle.js 中的情形。)
你需要借助模块来解决这个问题。
### 1. 模块化
JavaScript 社区已经提出了好几种模块化方案,其中一种被广泛接受的方案是CommonJS。在CommonJS 中,假如你在一个文件中编写了逻辑,就可以导出(export)一个或多个符号(最常见的是对象,不过也可以是函数,甚至单独的变量):
```
var Logo = React.createClass({/* ... */});
module.exports = Logo;
```
通常约定:一个模块只导出一个内容(比如一个React 组件)。
现在这个模块需要依赖React 以调用React.createClass()。目前没有定义全局变量,因此React 不能通过全局访问。你需要先进行导入(或者说是require),就像这样:
```
var React = require('react');
var Logo = React.createClass({/* ... */});
module.exports = Logo;
```
对于接下来开发的每一个组件,我们都将遵循这个模板:在代码顶部声明依赖,在底部导出内容,把组件逻辑放在中间。
### 2. ECMAScript 模块
ECMAScript 规范建议延续了这种模块化思想,并引入了一种新语法(与require() 和module.exports 相对)。你可以直接使用这种新语法,Babel 会帮你将其转译为浏览器可以识别的旧语法。
在定义其他模块的依赖关系时,可以把
```
var React = require('react');
```
改为
```
import React from 'react';
```
在导出模块内容时,可以把
```
module.exports = Logo;
```
改为
```
export default Logo
```
在export 语句的末尾省略分号是符合ECMAScript 语法规范的,并非本书错误。
# 3. 类
现在ECMAScript 已经引入了类的概念,因此可以使用新的语法。
修改前:
```
var Logo = React.createClass({/* ... */});
```
修改后:
```
class Logo extends React.Component {/* ... */}
```
之前的方法通过一个对象定义React“类”,其语法和ECMAScript 2015 中的类语法有一些区别,后者的用法如下。
* 对象中没有定义属性,只有函数(方法)。如果需要定义属性,可以在构造函数中通过this 关键字定义(接下来会介绍更多例子和可选项)。
* 方法通过render() {} 定义,不需要在前面添加function 关键字。
* 方法之间不需要像这样使用逗号分隔:var obj = {a: 1, b: 2};。
```
class Logo extends React.Component {
someMethod() {
} // 此处不需要添加逗号
another() { // 此处不需要添加function关键字
}
render() {
return ;
}
}
```
# 4. 概括
随着本书内容的深入,你将接触更多ECMAScript 的新特性,但目前介绍的语法对于这个模板的开发工作已经足够了,因为模板的作用只是一个最低限度的实现,目的是为新应用的开发建立基础。
现在模板中已经包含了:index.html、全局CSS 样式(app.css)、每个组件独立的CSS 样式(/css/components/Logo.css)、JavaScript 代码的入口点(app.js)和按照React 组件划分的具体模块(比如/js/source/components/Logo.js)。
以下是app.js 文件的最终版本:
```
'use strict';//总是使用严格模式是一种好习惯
import React from 'react';
import ReactDOM from 'react-dom';
import Logo from './components/Logo';
ReactDOM.render(
Welcome to The App!
,
document.getElementById('app')
);
```
以下是Logo.js 文件的最终版本:
```
import React from 'react';
class Logo extends React.Component{
render() {
return
}
}
export default Logo
```
你是否注意到了在导入React 库和导入Logo 组件时的区别?前者是from 'react',而后者是from './components/Logo'。后者看起来像一个文件夹路径,而事实也的确如此,模块会从相对路径中导入依赖;而前者则是从一个共享目录(即通过npm 安装的模块目录)中导入依赖。接下来,我们来看看怎么让所有的工作共同起作用,以及新语法是如何在浏览器中完美运行的(甚至包括老版本IE 浏览器)。
你可以在本书附带的代码库中找到这份模板(https://github.com/stoyan/reactbook/ ),并在此基础上开发你的应用。