Vue & React 的一些不同(2)

Vue & React的sharing ppt

Vue的响应式原理

Vue:

Vue的内在,响应式原理部分,官方文档有提到

当你把一个普通的 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。

每个组件实例都有相应的 watcher 实例对象,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。

在Vue组件中,对于array和object, 有一些更新方式,不是响应式的。

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

export default {
name :'',
data() {
return {
array : ['1'],
object : {},
array1 : [{active:false}]
}
},
methods : {
update() {
this.array[0] = 1; // 不是响应式的
this.object.active = false; // 不是响应式的
this.array1[0].active = true; //是响应式的
}
}
}

原因与Vue的实现方式相关。Vue对Object遍历它的每一项,用Object.defineProperty去设置get,set。而对于array, 重写;[‘push’,’pop’,’shift’,’unshift’,’splice’,’sort’,’reverse’]这几个array的方法,对其中的每一项增加watcher.

所以对于object, 直接往里面添加属性,不是响应式的;对于array, 直接修改里面的值也不是响应式的;而array[{object}],这种object的每个属性都做了get,set;所以改变它是响应式的。

在调试的时候,把对象console.log出来,看看有没有set, get就知道这个属性是否是响应式的。

一个小例子:

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

let obj = {"name":"li"}
Object.defineProperty(obj, "name", {
enumerable: true,
configurable: true,
get : function(){
return value
},
set : function(newVal){
value = newVal;
}
});

obj.name = "lili";
obj.age = 12;

console.log(obj);

/*
console出来的内容:

{age:12}
age:12
name:(...) //"lili"
get name : f ()
set name : f (newVal)
__proto__: Object

*/

Vue的响应式原理部分,同时也是它的双向数据流的原理。而React的是单向数据流。在Vue & React的一些不同里面有提到

React新手的一种编码误区

Dan(React之父)在他的twitter里面有写到一些新手写React的思想).

  • 如果你的components把接收到的props赋值给了state, 然后尝试通过接收到不同的props来改变state; 那么你就要好好想象这样做的必要性。是不是应该直接用props,把state给删除了。

  • 还举了一个例子 来说明,这个例子是很“稀有”的需要在组件内用state来接props的。

  • 对很多React的新手来说,他们的想法是“我需要在组件内部使用一些数据,这些数据来自于外部(父元素),那么我需要copy这些数据到组件内部”。这种想法是不对的。应该把state提升到父组件里面去使用。Lifting State Up - React

我觉得这种写React代码的方法不仅适用于React,同样也适用于Vue. 对于一个组件,如果它需要根据props来改变它的一些view,同时这个组件可能自己本身也会有一些操作来改变它的view, 那么最好的做法应该是组件接收props,用event来通知parent的props改变。

example:

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

export default class Parent extends Component {

constructor(props) {
super(props);
this.state = {
show : true
};
}
changeShow(value){
this.setState({show: value});
}
render() {
return (
<div>
<Children1
show={this.state.show}
changeShow={this.changeShow.bind(this)}
/>

</div>
);

}
}
class Children extends Component {

handleClose(){
this.props.changeShow(false);
}
render() {

let className = '';
if (this.props.show) {
className = 'show';
}else{
className = 'hide'
}
return (
<div className={className}>
children
<button onClick={this.handleClose.bind(this)}>close</button>
</div>
)

}
}