React入门系列(一)语法与概念初读

研究了很久的Vue,突然对它的老朋友React有点感兴趣,就去初步读了一下它的文档,发现确实很多东西与Vue有相同或者不同的地方,就用这篇博客记录下,我对它文档阅读的一些笔记。

比较的同时,以我所理解的Vue源码思路的角度,去解读一些React背后可能的原理

数据存储

React中的数据有两种存储方式,一种叫state,一种叫prop。

Prop

prop就对应于Vue中的prop,prop是从父组件传给子组件的,在子组件中是不可改变的,想要改变只能通过子组件触发更新事件,父组件监听后在父组件中改变。

State

state就对应于Vue中在每个组件内部定义的data,是组件内部的属性,组件对其中的每个属性都有完全的操作权。

不过有一点区别就是,Vue中对data的赋值操作会直接触发视图更新,因为Vue其实劫持了所有data中数据的setter方法,通过setter方法去通知视图更新。

而React中则通过setState去手动通知视图更新。其实这个setState我感觉是做了和Vue中setter相同的事。

同时React文档中多个setState会合并一起执行,也就是本来多次的视图更新会被合并到一次。

而Vue文档中说的是,每个setter触发的视图更新的操作会进入一个队列,叫做一个tick,每个tick会把所有队列中的数据顺序执行,其实和多个setState一起执行最终结果是相同的。

JSX & Template

Template

Vue中提供了template的方式去构建组件,在解析的时候,其实是通过Vue自己改造的html-parser将template当做一个普通的html解析,对于用户自定义的组件,和Vue自定义的属性,如v-on等会加以特殊处理,然后返回render函数

JSX

React的JSX则是通过babel将JSX语法转换为React的createElement方法,如

1
2
3
4
5
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
1
2
3
4
5
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);

函数返回JSX

1
2
3
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
1
2
3
4
5
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}

这两种方式其实都定义了一个Welcome组件,需要注意的是,React中自定义组件的名字首字母必须大写。

事件处理

例如,传统的 HTML:

1
2
3
<button onclick="activateLasers()">
Activate Lasers
</button>

在 React 中略微不同:

1
2
<button onClick={activateLasers}>  Activate Lasers
</button>

在 React 中另一个不同点是你不能通过返回 false 的方式阻止默认行为。你必须显式的使用 preventDefault 。例如,传统的 HTML 中阻止链接默认打开一个新页面,你可以这样写:

1
2
3
<a href="#" onclick="console.log('The link was clicked.'); return false">
Click me
</a>

在 React 中,可能是这样的:

1
2
3
4
5
6
7
function ActionLink() {
function handleClick(e) { e.preventDefault(); console.log('The link was clicked.'); }
return (
<a href="#" onClick={handleClick}> Click me
</a>
);
}

this的绑定问题

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
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};

// 为了在回调中使用 `this`,这个绑定是必不可少的
this.handleClick = this.handleClick.bind(this);
}

handleClick() {
this.setState(state => ({
isToggleOn: !state.isToggleOn
}));
}

render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}

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

这里为什么要在构造函数中对函数内部的方法调用bind?

首先要理解bind的作用,他会返回一个新的函数,这个函数的this指针是确定的,就是他的参数,当我们调用这个新的函数时,其中的this不是动态的。

置于为什么要这样,原因在于,这个handleClick中需要用到子组件的setSstate,而这个handleClick其实是在父组件中调用的,如果不绑定,那这个this其实指向的是父组件。

如果觉得使用 bind 很麻烦,这里有两种方式可以解决。如果你正在使用实验性的 public class fields 语法,你可以使用 class fields 正确的绑定回调函数:

1
2
3
4
5
6
7
8
9
10
class LoggingButton extends React.Component {
// 此语法确保 `handleClick` 内的 `this` 已被绑定。 // 注意: 这是 *实验性* 语法。 handleClick = () => { console.log('this is:', this); }
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
}

Create React App 默认启用此语法。

如果你没有使用 class fields 语法,你可以在回调中使用箭头函数

1
2
3
4
5
6
7
8
9
10
11
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}

render() {
// 此语法确保 `handleClick` 内的 `this` 已被绑定。 return ( <button onClick={() => this.handleClick()}> Click me
</button>
);
}
}

这两种方法能解决问题的原因在于使用了箭头函数,而箭头函数的this是静态作用域的,也就是声明箭头函数时定义好的,也不会改变,与bind是相同的作用。

受控组件

在 HTML 中,表单元素(如<input><textarea><select>)之类的表单元素通常自己维护 state,并根据用户输入进行更新。而在 React 中,可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用 setState()来更新。

我们可以把两者结合起来,使 React 的 state 成为“唯一数据源”。渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。

例如,如果我们想让前一个示例在提交时打印出名称,我们可以将表单写为受控组件:

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
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}

handleChange(event) { this.setState({value: event.target.value}); }
handleSubmit(event) {
alert('提交的名字: ' + this.state.value);
event.preventDefault();
}

render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
名字:
<input type="text" value={this.state.value} onChange={this.handleChange} /> </label>
<input type="submit" value="提交" />
</form>
);
}
}

React哲学

这一部分直接看官方文档就好,没什么难理解的地方:https://react.docschina.org/docs/thinking-in-react.html