React Native开发之React基础
# React是什么?
React 是 Facebook 推出的开源 JavaScript Library,React 是一个声明式,高效且灵活的用于构建用户界面的 JavaScript 库。使用 React 可以将一些简短、独立的代码片段组合成复杂的 UI 界面,这些代码片段被称作“组件”。React 还可以使用 Node 进行服务器渲染,或使用 React Native 开发原生移动应用。
# 最简易的 React 示例如下:
1 | ReactDOM.render( |
它将在页面上展示一个 “Hello, world!” 的标题。
# 为什么使用 JSX?
JSX 明显更加简洁易读。1
2
3
4
5const element = (
<h1 className="greeting">
Hello, world!
</h1>
);1
2
3
4
5const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
# 在 JSX 中嵌入表达式
示例中,我们将调用 JavaScript 函数 formatName(user) 的结果,并将结果嵌入到 <h1> 元素中。
1 | function formatName(user) { |
# 组件 & Props
组件,从概念上类似于 JavaScript 函数。它接受任意的入参(即 “props”),并返回用于描述页面展示内容的 React 元素。
1 | class Welcome extends React.Component { |
提示:
React 的 JSX 里约定分别使用首字母大、小写来区分本地组件的类和 HTML 标签。
由于 JSX 就是 JavaScript,一些标识符像 class 和 for 不建议作为 XML 属性名。作为替代, React DOM 使用 className 和 htmlFor 来做对应的属性。所有 React 组件都必须像纯函数一样保护它们的 props 不被更改。
# State & 生命周期
componentDidMount() 方法会在组件已经被渲染到 DOM 中后运行,所以,最好在这里设置计时器,
一旦 Clock 组件从 DOM 中被移除,React 就会调用 componentWillUnmount() 生命周期方法,这样计时器就停止了。
必须在 componentWillUnmount() 生命周期方法中清除计时器。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
36
37class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
不要直接修改 State,例如,此代码不会重新渲染组件:1
2
3
4// Wrong
this.state.comment = 'Hello';
// Correct
this.setState({comment: 'Hello'});
如果更新State 需要用到Props 属性,将此次更新被应用时的 props 做为第二个参数:1
2
3
4// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
# 元素渲染
1 | function tick() { |
遍历渲染this.props.children会返回组件对象的所有属性。 React 提供一个工具方法 React.Children 来处理 this.props.children 。我们可以用 React.Children.map或React.Children.forEach 来遍历子节点。
1 | React.Children.map(children, function[(thisArg)]) |
示例1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18class NotesList extends React.Component{
render(){
return (
<ol>
{
React.Children.map(this.props.children,(child)=>
{
return <h1>{child}</h1>;
})
}
</ol> );
}
}
ReactDOM.render(<NotesList>
<span>hello</span>
<span>world</span>
</NotesList>,
document.getElementById('root'));
列表可以参考此方式渲染。
# ref属性 获取真是DOM
组件并不是真实的 DOM 节点,而是存在于内存之中的一种数据结构,叫做虚拟 DOM (virtual DOM)。只有当它插入文档以后,才会变成真实的 DOM 。根据 React 的设计,所有的 DOM 变动,都先在虚拟 DOM 上发生,然后再将实际发生变动的部分,反映在真实 DOM上,这种算法叫做 DOM diff ,它可以极大提高网页的性能表现。
但是,有时需要从组件获取真实 DOM 的节点,这时就要用到 ref 属性。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24class Alert extends React.Component {
showAlert(message) {
alert(`Debug:${message}`);
}
render() {
return null;
}
}
class MyTitle extends React.Component {
onClick = () => {
this.refs.alert.showAlert('MyTitle');
};
render() {
return <div>
<h1 onClick={this.onClick}>Click me</h1>
<Alert ref='alert'/>
</div>;
}
}
ReactDOM.render(<MyTitle/>, document.getElementById('root'));
# 使用 PropTypes 进行类型检查
自 React v15.5 起,React.PropTypes 已移入另一个包中。请使用 prop-types 库 代替。1
2
3
4
5
6
7
8
9
10
11
12
13import PropTypes from 'prop-types';
class Greeting extends React.Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}
Greeting.propTypes = {
name: PropTypes.string
};
# 组件的生命周期

# 组件的生命周期分成三个时期
- Mounting:挂载时
- Updating:更新时
- Unmounting:卸载时
# Mounting:挂载时
当组件实例被创建并插入 DOM 中时,其生命周期调用顺序如下:
constructor()
React组件的构造函数将会在装配之前被调用。当为一个React.Component子类定义构造函数时,你应该在任何其他的表达式之前调用super(props)。否则,this.props在构造函数中将是未定义,并可能引发异常。
static getDerivedStateFromProps()
组件实例化后和接受新属性时将会调用getDerivedStateFromProps。它应该返回一个对象来更新状态,或者返回null来表明新属性不需要更新任何状态。注意,如果父组件导致了组件的重新渲染,即使属性没有更新,这一方法也会被调用。如果你只想处理变化,那么可以通过比较新旧值来完成。
调用this.setState() 通常不会触发 getDerivedStateFromProps()。
render()
会被 React 渲染为 DOM 节点,
render() 方法是 class 组件中唯一必须实现的方法。
当 render 被调用时,它会检查 this.props 和 this.state 的变化并返回以下类型之一:
React 元素。通常通过 JSX 创建。例如,会被 React 渲染为自定义组件,无论是 还是 均为 React 元素。
数组或 fragments。 使得 render 方法可以返回多个元素。欲了解更多详细信息,请参阅 fragments 文档。
Portals。可以渲染子节点到不同的 DOM 子树中。欲了解更多详细信息,请参阅有关 portals 的文档
字符串或数值类型。它们在 DOM 中会被渲染为文本节点
布尔类型或 null。什么都不渲染。(主要用于支持返回 test &&的模式,其中 test 为布尔类型。)
render() 函数应该为纯函数,这意味着在不修改组件 state 的情况下,每次调用时都返回相同的结果,并且它不会直接与浏览器交互。如需与浏览器进行交互,请在 componentDidMount() 或其他生命周期方法中执行你的操作。保持 render() 为纯函数,可以使组件更容易思考。
componentDidMount()
componentDidMount()在组件被装配后立即调用,通常在该方法中进行一些初始化操作。初始化时需要DOM节点的操作可以放到这里进行`。若你需要从远端加载数据,这是一个适合实现网络请求的地方。在该方法里设置状态将会触发重渲。这一方法是一个发起任何订阅的好地方。如果你这么做了,别忘了在componentWillUnmount()退订。
另外,在这个方法中调用setState()将会触发一次额外的渲染,但是它将在浏览器刷新屏幕之前发生。这保证了即使render()将会调用两次,但用户不会看到中间状态。
# Updating:更新时
当组件的 props 或 state 发生变化时会触发更新。组件更新的生命周期调用顺序如下:
shouldComponentUpdate()
在接收到新的 props 或者 state,将要渲染之前调用,以让React知道当前状态或属性的改变是否不影响组件的输出。该方法在初始化渲染的时候不会调用,在使用 forceUpdate 方法的时候也不会。如果确定新的 props 和 state 不需要重新渲染,则此处应该 返回 false。
- getSnapshotBeforeUpdate()
getSnapshotBeforeUpdate() 在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值将作为参数传递给 componentDidUpdate()。 - componentDidUpdate()
当组件更新后,可以在此处对 DOM 进行操作。如果你对更新前后的 props 进行了比较,也可以选择在此处进行网络请求。(例如,当 props 未发生变化时,则不会执行网络请求)componentDidUpdate() 会在更新后会被立即调用。首次渲染不会执行此方法。
# Mounting:挂载时
当组件从 DOM 中移除时会调用如下方法:
componentWillUnmount()
在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等。componentWillUnmount() 中不应调用 setState(),因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它。
# 不安全的方法
- componentWillMount
- componentWillReceiveProps
- componentWillUpdate
使用这些生命周期方法通常会导致错误和不一致,因此将来会被弃用。在新的React版本中他们被标记为UNSAFE。