0%

React(一)

React的设计思想

React是基于具有特性(props)、状态(state)和生命周期方法(lifecycle methods)的组件来构建用户界面的JavaScript库。

组件化

什么是组件化?就像我们造汽车一样,分别制造车身、动力总成,底盘等,然后组装起来,并且各个系统又是由各自的子系统组装而成。

props和state

我在这里将它们分别称为特性和状态,什么叫特性?就是那些能把你跟别人区分出来的信息,比如你的出生日期,你的性别,你的父母等,这些信息是不会轻易发生改变的。状态则指的是当前的信息,比如刚大学毕业,没有女朋友,这些信息以后有可能会发生变化。我们通过特性和状态就可以来描述一个人。
来到我们的Web中,我们把若干个具有自己的特性和状态单元组合在一起就可以呈现出完整的界面来。

生命周期方法

就像一辆汽车一样,它会经历多个阶段,从制造到销售到使用再到最后的报废,我们的组件有也会有生命周期,用来获取组件的信息,或者对发生的变化做出反应,比如获得某个特性的时候,有状态更新的时候。一般来说,所有的组件都会经历初始化、运行中和销毁三个阶段,每个阶段都有开发者可以自定义的函数,执行不同的行为。

Virtual DOM和JSX

Virtual DOM

为了操作DOM,我们需要把DOM树存储在内存中,用JS对象的形式来描述DOM,发生变化时只更改变化的部分。

JSX

React推荐使用JSX的语法,所谓JSX就是直接在js中写html片段。

第一个应用

这里使用create-react-app来创建应用,首先npm install -g create-react-app安装,然后在工作目录下使用create-react-app hello_react就可以创建一个React应用。

src/index.js更改为以下内容:

1
2
3
4
5
6
7
import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(
<div>Hello World!</div>,
document.getElementById('root')
);

这里的做的事情就是把一个包含着Hello World内容的div元素渲染到ID为root的DOM元素上。
执行npm start然后再浏览器中打开localhost:3000就可以看到Hello World!出现在了屏幕上。

我们渲染的东西也可以是我们自定义的东西。比如可以将一个html片段一次性渲染到ID为root的元素上。
src/index.js更改为以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import React from 'react';
import ReactDOM from 'react-dom';

class Stuff extends React.Component {
render() {
return (
<div>
<h2>这是一个H2</h2>
<ul>
这是一个列表:
<li>第一个列表项</li>
<li>第二个列表项</li>
<li>第三个列表项</li>
</ul>
</div>
);
}
}

ReactDOM.render(
<Stuff />,
document.getElementById('root')
);

这样的话,我们在Stuff中定义的html片段也会渲染在最终的html中,这里是render()方法的返回值。
这就是前面提到的JSX,render方法中普通的JS表达式则需要用花括号包裹起来,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...

class Stuff extends React.Component {
render() {
const navItems = ['首页', '关于', '联系'];
return (
<div>
<h2>渲染列表项</h2>
<ul>
{
navItems.map(navItem => <li key={navItem}>{navItem}</li>)
}
</ul>
</div>
);
}
}

...

render()方法中先定义了一个列表,然后map方法对列表进行迭代,将每一项的值赋给一个li,循环渲染的时候需要给每一个子项一个唯一的标识。
这样的话,我们就实现了列表的渲染。如果数据是从由父组件传递给子组件,或者在实例化的时候被赋值,可以使用props

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

import React from 'react';
import ReactDOM from 'react-dom';

class Stuff extends React.Component {
render() {
return (
<div>
<h2>渲染列表项</h2>
<ul>
{
this.props.navItems.map(navItem => <li key={navItem}>{navItem}</li>)
}
</ul>
</div>
);
}
}

ReactDOM.render(
<Stuff navItems={['首页', '关于', '联系']} />,
document.getElementById('root')
);

我们通过类似于html标签的属性值的形式,将数据(这里是一个数组)传递到Stuff中,然后在Stuff中可以通过props来使用。当然复杂界面需要元素各自都有一部分的处理能力。我们可以通过state和事件来实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import React from 'react';
import ReactDOM from 'react-dom';

class Stuff extends React.Component {
constructor(props) {
super(props);
this.state = {
navItems: this.props.navItems
};
this.HandleCilck = this.HandleCilck.bind(this);
}
HandleCilck() {
this.setState({
navItems: [...this.state.navItems, '新增的导航条目']
});
}
render() {
return (
<div>
<h2>渲染列表项</h2>
<ul>
{
this.state.navItems.map((navItem, index) => <li key={index}>{navItem}</li>)
}
</ul>
<button onClick={this.HandleCilck}>点我</button>
</div>
);
}
}

ReactDOM.render(
<Stuff navItems={['首页', '关于', '联系']} />,
document.getElementById('root')
);

在这里我们使用state使得Stuff组件会有自己的状态,并且可以通过button的点击事件来更新state,只要state更新,界面就会更新。
首先我们在constructor中使用this.state来定义状态(这里使用实例化时传递进来的props作为其默认的状态),然后在点击事件的处理函数HandleCilck()中调用this.setState()来更新state
点击这里查看运行结果。