本文采用 es6 语法,完全参考 https://reactjs.org/docs/
本文完全参考 React 官方 Quick Start 部分,除了最后的 thinking-in-react 小节
安装
首先你需要点击安装 nodejs(npm)。然后执行:
npm install -g create-react-app
如果上述命令执行失败可以运行以下命令:
npm install -g create-react-app --registry=https://registry.npm.taobao.org
然后建立一个 react 并运行:
create-react-app myApp
cd myApp
npm start
这样你就简单的完成了一个 react app 建立,其目录结构如下( 图中不包括 node_modules 目录,下同 ):
Hello World
我们删除一些不必要的东西,然后修改目录结构如下(不能删 node_modules 目录,如果删了就在项目目录下运行 npm i
就好了):
其中 components 是个目录。
修改 index.js 如下:
import React from 'react';
import ReactDOM from 'react-dom';
ReactDOM.render(
<h1> hello world! </h1>,
document.getElementById('root')
);
然后命令行运行:
npm start
你就可以看到熟悉的 ‘hello world’ 了
JSX
JSX 是 react 中允许 js 和 html 混写的语法格式,需要依赖 babel 编译。这里我就只研究它的语法:
const element = <h1>Hello, world!</h1>;
可以通过花括号在其中插入表达式:
function formatName(user){
return user.firstName + ' ' + user.lastName;
}
const user = {
firstName: 'Harper',
lastName: 'Perez'
};
const element = (
<h1>
Hello, {formatName(user)}!
</h1>
);
ReactDOM.render(
element,
document.getElementById('root')
);
可以将 HTML 语句写为多行以增加可读性,用小括号括起来可以防止自动插入分号导致的错误。
JSX 也是个表达式,所以可以用在 for 和 if 中:
function getGreeting(user){
if (user){
return <h1>Hello, {formatName(user)}!</h1>;
}
return <h1>Hello, Stranger.</h1>;
}
我们可以正常使用引号给 HTML 标签添加属性,也可以使用 js 表达式
const element = <div tabIndex="0"></div>;
const element = <img src={user.avatarUrl} />; //注意空标签以 /> 结尾,像 XML 一样
注意 html 属性名请使用小驼峰(camelCase)写法
React 会在渲染之前 escape 所有在 JSX 嵌入的值,可以有效的防止 XSS 攻击。
babel 会编译 JSX 成 React.createElement() 的参数调用:
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
// 编译为以下形式
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
而 React.createElement() 会生成这样一个对象(React 元素):
const element = {
type: 'h1',
props: {
className: 'greeting',
children: 'Hello, world'
}
};
元素渲染
在 ./public/index.html
中有一个 id 为 root 的 div。我们将这个 div 作为 react 渲染的容器。
回看 hello world 程序,通过 ReactDOM.render() 方法很轻松的把内容渲染到了目标容器上:
ReactDOM.render(
<h1> hello world! </h1>,
document.getElementById('root')
);
当然也可以这样写:
let content = <h1> hello world! </h1>;
ReactDOM.render(
content,
document.getElementById('root')
);
下面我们写一个复杂的,这是个实时更新的时钟,通过 setInerval 每隔 1s 调用 ReactDOM.render:
function Tick(){
const element = (
<div>
<h1>Hello, world!</h1>
<h2>It is {
new Date().toLocaleTimeString()}.</h2>
</div>
);
ReactDOM.render(
element,
document.getElementById('root')
);
}
setInterval(Tick, 1000);
重写上面时钟组件的代码如下,使其组件化程度更高:
function Clock(props){
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {props.date.toLocaleTimeString()}.</h2>
</div>
);
}
function Tick(){
ReactDOM.render(
//这个地方不得不传入一个参数, 但理论上获取一个时钟直接获取就可以了,这个问题我们后面再解决
<Clock date={
new Date()} />,
document.getElementById('root')
);
}
setInterval(Tick, 1000);
组件
React 给我们提供了更好的管理我的代码——组件。这里我们还是首先我们先了解一下自定义标签:
const element = <Welcome name="Sara" />;
对这个标签的理解也不难,它实际上调用了 Welcome 函数,并且将所有的属性(这里只有name)打包为一个对象传给 Welcome 函数。所以下面这个代码输出 ”Hello Sara”
function Welcome(props){
return <h1>Hello, {props.name}</h1>;
}
const element = <Welcome name="Sara" />;
ReactDOM.render(
element,
document.getElementById('root')
);
组件帮助我事先一些重复的工作,比如这样:
function Welcome(props){
return <h1>Hello, {props.name}</h1>;
}
function App(){
return (
<div>
<Welcome name="Sara" />
<Welcome name="Cahal" />
<Welcome name="Edite" />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
我们可以通过传递参数得到同一个组件构建的不同模块。
这里我们需要补充一个重要的概念:纯函数!!!
如果一个函数执行过程中不改变其参数,也不改变其外部作用于参数,当相同的输入总能得到相同的值时,我们称之这样的函数为纯函数。React 要求所有组件函数都必须是纯函数。
其实之前的一段代码中 Tick, Welcome 函数就可以看做是一个组件,同时 React 建议组件名的首字母大写。但是更多情况下我们会用到 es6 的语法构建组件。以之前时钟代码为例,转换过程分为五个步:
- 新建一个类,类名同组件函数名Clock,并继承自 React.Component;
- 给该类添加一个方法 render(/无参数/);
- 将 Clock 的函数体作为该函数的函数体;
- 将 render 方法中的 props 换为 this.props;
- 删除原有的 Clock 函数
结果如下:
class Clock extends React.Component {
render(){
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {
this.props.date.toLocaleT