Vue & React 的一些不同

最近用Vue做项目,然后呢之前用过React,就觉得应该比较一下他们的不同。不是很全面,完全是从平时工作的时候用到的出发。

component的写法

Vue

1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
<div>
<!-- Write your HTML with Vue in here -->
</div>
</template>
<script>
export default {
// Write your Vue component logic here
}
</script>

<style scoped>
/* Write your styles for the component in here */
</style>

React

1
2
3
4
5
6
7
8
9
10
11
12
import React from "react";
import "*.css"; //if you need some css

class YourComponentName extends React.Component {
render() {
return (
<div>
//JSX
</div>
)

}
}

Vue对熟悉Jquery开发方式的前端同学更加“友好”,类似的html+css+js的开发,不过这里是template,需要学习一些template的东西;然后css很友好,感觉没有任何变化,js当然是Vue component的方式.
React整个更像是Javascript,另外需要学习一下JSX.

这部分中,常用到的下面三个部分

Vue React
binging style v-bind:class / v-bind:style (template syntax) className / style={yourStyle}(in JSX)
handling events v-on:click (template syntax) onClick=”” (in JSX)
list rendering v-if / v-for (template syntax) if / for (Javascript)

lifecycle的不同

vue

1
2
3
4
5
6
7
8
9
10
11
12

export default {
name : 'YourName',
data() {
return {
msg : "This is your app."
}
},
created(){},
mounted(){}
...
}

React

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

constructor(props) {
super(props);
this.state = {
msg : "This is your app."
};
}
//a component is being created and inserted into the DOM
componentDidMount(){}//do ajax request to populate data here

componentWillUnmount(){}//

//react 16版本的三个will函数:componentWillMount, componentWillReceiveProps, componentWillUpdate 都会在前面带上UNSAFE_的前缀, 并且version 17之后就会取消这三个hook

static getDerivedStateFromProps(nextProps, prevState){}//当组件实例化/接收到new props的时候

getSnapshotBeforeUpdate(prevProps, prevState) {}//官方例子,在dom更新之前读取它的属性,获取滚动条的位置


当然Vue与React 有不同的lifecycle的hook。Vue多了create阶段的hook, beforeCreate/created。Mount的意思一个组件被创建并且放到DOM中。简单类比React 与 Vue: React的componentDidMount() => Vue的mounted()。

有个很大的区别是,vue不建议在这些钩子里面更新组件的状态。因为vue有另外两个地方来更新,computed与watcher

关于这部分,有一个例子,可以能够很好的看出它们的区别

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

// Parent

<template>
<div class="container">
<div v-if="type"><ChildBlue /></div>
<div v-else><ChildRed /></div>
</div>
</template>

<script>
import ChildBlue from "./ChildBlue.vue";
import ChildRed from "./ChildRed.vue";

export default {
name : "Parent",
components : {
ChildBlue,
ChildRed
},
data() {
return {
type : false //default 设置的是false
}
},
created() {
this.type = true;
}
/*
mounted(){
this.type = true; //
}*/

}
</script>


//ChildBlue.vue 随便是什么

//ChildRed.vue

<template>
<div class="red">type is red</div>
</template>
<script>
export default {
name : 'ChildRed',
beforeCreate() {
this.timer = setTimeout(function(){
alert("before create red!")
},1000)
},
created() {
this.timer = setTimeout(function(){
alert("create red!")
},1000)
},
mounted() {
this.timer = setTimeout(function(){
alert("mount red!")
},1000)
},
/*
beforeDestroy(){
clearTimeout(this.timer)
}*/

}
</script>

<style scoped>
.red{
background-color: red
}

</style>

Parent.vue 在created阶段改变type的值,那么ChildRed就不会被“创建”,1000ms以后,不会有alert; 如果是在mounted阶段改变type的值,那么ChildRed会经历mounted -> destroyed的过程,如果没有在destroy阶段clear timer,那么在1000ms以后,就会看到alert


React 没有created的阶段,所以记得一定在unmount阶段,clear timer / removeEventListener 等操作

更新状态的不同

Vue

1
2
3
4

computed: {}//这里面是计算属性,只有需要re-rendering的时候才会调用;对应的属性变化的时候,计算属性也会跟着变化;属性就是data里面的内容
methods : {}//这里面的方法,任何时候都会调用,不管是否会re-rendering
watcher : {}//大多数时候,能用computed计算属性的都不用watcher. 除非:This is most useful when you want to perform asynchronous or expensive operations in response to changing data. (异步操作/比较重的操作 来改变数据的时候)

React

setState(updater[, callback]) 任何时候要改变一个component的状态的时候,都是用的setState(). ps: setState()是异步的操作。

1
2
3
4

this.setState((prevState, props) => {
return {};
});

数据流

Vue v-model 双向数据绑定

在表单控件上,可以直接使用v-modal来实现双向数据绑定。官方解释v-modal其实就是使用用户输入事件,加上对边界条件的特殊处理的语法糖。

1
2
3
4
5
6
7
8
9

<input v-model="searchText">

//等价于

<input
v-bind:value="searchText"
v-on:input="searchText = $event.target.value"
>

一个input的例子:

1
2
3
4
5

<template>
<input v-model="message" placeholder="edit me">
<p>Message is: {{ message }}</p>
</template>

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

class YourComponentName extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};

this.handleChange = this.handleChange.bind(this);

}

handleChange(event) {
this.setState({value: event.target.value});
}


render() {
return (
<div>
<input type="text" value={this.state.value} onChange={this.handleChange} />
<p>Message is: {this.state.value}</p>
</div>
);

}
}

单从这点来看,vue更灵活,代码更少(因为其实都帮你做了处理了)。React 需要写更多的代码,但个人觉得,反而感觉react更简单 一些(理解加使用的时候,更容易清楚数据的来龙去脉)。不过对于UI组件来说,React的单向数据流肯定就会导致写很多代码。


“Layout”的构造

React 可以利用props

example : https://codepen.io/gaearon/pen/gwZOJp?editors=0010

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

function SplitPane(props) {
return (
<div className="SplitPane">
<div className="SplitPane-left">
{props.left}
</div>
<div className="SplitPane-right">
{props.right}
</div>
</div>
);

}

function App() {
return (
<SplitPane
left={
<Contacts />

}
right={
<Chat />
} />
);

}

Vue 可以利用slot

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
37
38
39
40
41
42
43
44

//base-layout.vue
<template>
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>


//feature.vue
<template>

<base-layout>
<template slot="header">
<h1>Here might be a page title</h1>
</template>

<p>A paragraph for the main content.</p>
<p>And another one.</p>

<template slot="footer">
<p>Here is some contact info</p>
</template>
</base-layout>
</template>
<script>
export default {
name : "Feature",
components : {
baseLayout
}
}
</script>

<style>

</style>

未完待续