React対VUE
序文
初めて大きな工場に入ったとき、どうしてもReactに出会いました。あらゆるためらい、ためらい、ためらいの後、彼はまだ彼を受け入れるしかありませんでした。この記事では主に、vueテクノロジースタックから反応する100の悲しみを紹介します。VUEとReactを包括的に比較したかったので、単純な命題のようですが、この記事を書くのは本当に難しいです。この記事は、自分の才能と10日間以上の反応経験を組み合わせて、多くの情報を参照した後に作成しました。記事に含まれるいくつかの未熟な見解については、訂正のためのメッセージを残していただければ幸いです。
同じ点:
次のように、2つの主な機能のほとんどは同じです。
- 仮想DOM、すばやくDOMを変更
- コンポーネント開発
- レスポンシブコンポーネント
- サーバー側レンダリング
- アプリケーション開発ファミリーバケット:ルーティング+状態管理+パッケージングなど
この記事では主に、コーディングレベルから実装レベル、アプリケーションレベルまで、ReactとVueの比較について説明します。
差:
1.ファイル構造
a)vueは.vueで終わるファイルを使用します
一般に、vueファイルはコンポーネントを記述し、対応するコンテンツ要素はtemplate
+ script
+ style
ルートタグブロックでラップされます。template
dom構造をscript
部分的に説明し、部分的にロジックを記述し、style
コンテンツのスタイルを記述します。編成は非常に明確です。これは伝統を受け入れる方法であり、開発者にとって比較的フレンドリーです。
<template>
<div>
<i-input style="width:200px" v-model="value"></i-input>
<span>{
{
value}}</span>
</div>
</template>
<script>
export default {
data: function() {
return {
value: "test"
};
},
name: "home",
components: {
},
mounted() {
}
};
</script>
<style>
@import url(../style/home.less);
</style>
b)Reactは.jsxで終わるファイルを使用します
Reactは従来のes6モジュール化手法を使用してコンポーネントを説明します。コンポーネントはクラスであり、コンポーネントのプロパティとステータスはクラスで記述されます。最後に、htmlテンプレートコンポーネントがrender関数で返されます。Reactでは、すべてがjsオブジェクトです。したがって、スタイルもcss_moduleによって要素に追加されます。
import React from 'react';
import ReactDOM from 'react-dom';
import {
DatePicker } from 'antd';
import {
cssObj} from '/style/index.css'
class Text extends React.Component {
render() {
return (
<div>
<p className={
cssObj.p}>This is a react Component123451s</p>
<div className = "my-image" ></div>
<DatePicker/>
</div>
);
}
}
export default Text;
2、テンプレート構文
vue采用模板语法,react采用JSX来编写DOM, 模板语法是在HTML中加入一些赋值markup,而JSX语法是将JS代码与DOM标签混合在一起使用. 对于没有接触过两者的前端开发来说,模板语法更容易理解,上手快,且结构简单,编写容易. 具体区别见下面的例子:
a) VUE模板语法
采用HTML + moustache(双大括号赋值) + 指令的模板语法, 易学,简单,上手非常快.(也支持JSX, 但推荐使用模板语法)
指令: 接收表达式,当表达式变化时,响应式的作用在DOM上.
<div class="todo-list">
<h3>待办列表</h3>
<ul class="todo-ul">
<li v-for="(item, key, index) in todoList" :key="key"
:id="key" @click="clickTask(key)" :class="{success: item.status}">
{
{
index+1 }}. {
{
item.content }}
<span v-if="item.status">(完成)</span>
<span class="create-time">{
{
item.createTime}}</span>
</li>
</ul>
</div>
- v-for: 循环指令, 遍历todoList对象
- @click: v-on:click的缩写,绑定点击事件
- :class: v-bind:class的缩写,表示item.status为true时,添加success到li的class
- { {}}: 大括号赋值语句, 可以接收表达式
- v-if: 条件判断,当值为true时,该DOM才显示
b)react JSX语法
<div className="todo-list">
<h3>待办列表</h3>
<ul class="todo-ul">
{
Object.keys(todoList).forEach((k, i) => (
<li key={
i} id={
k} onClick={
() => {
this.clickTask(k)}}
className={
todoList[k].status?'success':''}>
{
i}. {
todoList[k].content}
{
todoList[k].status && <span>(完成)</span>}
<span class="create-time">{
{
todoList[k].createTime}}</span>
</li>
))}
</ul>
</div>
jsx语法将JS逻辑与DOM标签混在一起,学习成本会比较高,对比模板语法来说编写也复杂一些.
三、数据绑定
这是个人认为react与Vue最大的区别,这一点的不同直接导致了编程风格和思想的不同。
a) vue的双向绑定
Vue.js 最核心的功能有两个,一是响应式的数据绑定系统,二是组件系统。所谓双向绑定,指的是vue实例中的data与其渲染的DOM元素的内容保持一致,无论谁被改变,另一方会相应的更新为相同的数据。这是通过设置属性访问器实现的。你不需要去关注视图层怎么变化的,而只需要关注数据。
<template>
<div>
<i-input style="width:200px" v-model="value"></i-input>
<span>{
{
value}}</span>
</div>
</template>
<script>
export default {
data: function() {
return {
value: "test"
};
},
name: "home",
components: {
},
mounted() {
}
};
</script>
上例中,我在任一函数中操作this.data.value值,会使所有引用这个value值的元素自动同步视图,反之,input改变,会同步修改所有与之绑定的数据。
b) react的单向数据流
react中通过将state(Model层)与View层数据进行双向绑定达数据的实时更新变化,具体来说就是在View层直接写JS代码Model层中的数据拿过来渲染,一旦像表单操作、触发事件、ajax请求等触发数据变化,则进行双同步。就是说,数据影响视图,但是视图对数据的影响需要开发者手动控制。一个简单的例子:
class DataBind extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {
value: 123,
};
}
handleChange(e) {
this.setState({
value: e.target.value,
});
}
render() {
return (
<div>
<input value={
this.state.value} onChange={
this.handleChange} />
<div>{
this.state.value}</div>
</div>
);
}
}
如果不使用onChange手动setState,则不会更新状态。
补充:
- 那如果我想要在vue里监听数据变化怎么处理?
使用
watcher
,可以监听任何一种数据变化,从而在处理函数中做一些其他数据操作。当然,所有的数据操作都会直接影响视图。
四、组件的数据交互
i)父子组件通信
a) vue
在vue中,父组件传值通过为子组件添加属性实现。这个跟react基本保持一致,不同的是,在vue中,子组件需要在子组件的props属性中预先设置接受的属性。对于子传父,则通过事件进行。
:name 中的
:
是v-bind的简写。 如果不使用:
,则后面的字符串中的内容会被当做字符串解析。
@是v-on的缩写 vue中定义事件的方式。提供了很多默认事件,也可以定义自定义事件。
//--父组件
<template>
<div>
<h1>这是父组件</h1>
<template v-for="(child_data,index) in child_datas">
<Child @my-callback="getValFromChild" :name="child_data.name" :key="index"></Child>
</template>
</div>
</template>
<script>
import Child from "./Child";
export default {
data: function() {
return {
child_datas: [
{
name: "子组件1"
},
{
name: "子组件2"
}
]
};
},
name: "Parent",
methods: {
getValFromChild(msg) {
alert("收到子组件消息:" + msg);
}
},
components: {
Child
}
};
</script>
//--子组件
<template>
<div>
<button @click="sendToParent">发送给父消息</button>
{
{
this.name}}
</div>
</template>
<script>
export default {
props: ["name"],
data: function() {
return {
};
},
name: "child",
components: {
},
methods: {
sendToParent() {
this.$emit("my-callback", `我是你儿子(${
this.name})`);
}
},
mounted() {
}
};
</script>
b) react
react中数据传递是一般是通过将回调函数作为props传递到子组件。子组件在适当的时候进行调用
//--父组件
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
child_datas: [
{
name: '子组件1',
},
{
name: '子组件2',
},
],
};
}
onReceiveMeg = (msg) => {
alert('收到子组件消息:' + msg);
}
render() {
return (
<div>
<h1>这是父组件</h1>
{
this.state.child_datas.map((child_data, i) => (
<Child name={
child_data.name} key={
i} sendmsg_fn={
this.onReceiveMeg}></Child>
))
}
</div>
);
}
}
//--子组件
class Child extends React.Component {
constructor(props) {
super(props);
this.state = {
};
}
sendToParent=() => {
this.props.sendmsg_fn(this.props.name);
}
render() {
return (
<div>
<button type="button" onClick={
this.sendToParent}>发送给父消息</button>
{
this.props.name}
</div>
);
}
}
ii) 兄弟组件通信
兄弟组件间通信基本依赖第三方转发实现。二者原理基本相同,这里不再赘述。
五、 组件的渲染方式
a) vue 自动渲染
Vue宣称可以更快地计算出Virtual DOM的差异,这是由于它在渲染过程中,会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树。
1 在 Vue 应用中,组件的依赖是在渲染过程中自动追踪的,所以系统能精确知晓哪个组件确实需要被重渲染。
2 你可以理解为每一个组件都已经自动获得了 shouldComponentUpdate,并且没有上述的子树问题限制。
3 Vue 的这个特点使得开发者不再需要考虑此类优化,从而能够更好地专注于应用本身。
详解:
-
Vue的编译器在编译模板之后,会把这些模板编译成一个渲染函数。而函数被调用的时候就会渲染并且返回一个虚拟DOM的树。这个树非常轻量,它的职责就是描述当前界面所应处的状态。
-
当我们有了这个虚拟的树之后,再交给一个patch函数,负责把这些虚拟DOM真正施加到真实的DOM上。在这个过程中,Vue有自身的响应式系统来侦测在渲染过程中所依赖到的数据来源。
-
在渲染过程中,侦测到的数据来源之后,之后就可以精确感知数据源的变动。到时候就可以根据需要重新进行渲染。
-
当重新进行渲染之后,会生成一个新的树,将新树与旧树进行对比,就可以最终得出应施加到真实DOM上的改动。最后再通过patch函数施加改动
概况为:
-
当某个数据属性被用到时,触发 getter,这个属性就会被作为依赖被 watcher 记录下来。
-
整个函数被渲染完的时候,每一个被用到的数据属性都会被记录。
-
相应的数据变动时,例如给它一个新的值,就会触发 setter,通知数据对象对应数据有变化。
-
此时会通知对应的组件,其数据依赖有所改动,需要重新渲染。
-
对应的组件再次调动渲染函数,生成 Virtual DOM,实现 DOM 更新。
b) react的根组件渲染
-
在 React 应用中,当某个组件的状态发生变化时,它会以该组件为根,重新渲染整个组件子树。
-
如要避免不必要的子组件的重渲染,你需要在所有可能的地方使用 PureComponent,
-
或是手动实现 shouldComponentUpdate 方法。
换句话说,在Vue中,我修改数据的时候,不用去关心怎样修改数据能够造成尽可能小的渲染代价,或者可以说不用去管React的render函数被调用了几次,什么时候调用,该不该使用shouldComponentUpdate
生命周期钩子函数判断是否再调用render.
六、组件生命周期
a) vue 的生命周期钩子
b) react 的生命周期钩子
小结
篇幅原因。今天先写到这里,下一篇博文React 对比 VUE 断舍离分(二)