前情提要
我學習和使用Vue大概有一年時間了,可是最近纔開始學習的React,在沒使用過React以前就常常看到許多博主都在將二者進行對比,在實踐完之後,我想站在我本身的角度看看。css
那就開始了
官方文檔
Vue官方文檔
React官方文檔【中文版】vue
- 我的感受Vue的文檔劃分的更加好一點,會把許多概念都講的比較清晰(雖然第一次看的時候啥都沒看懂)同時把一些相關的生態系統也概括到了一塊兒,例如vue-cli、vue-router、vuex等,比較方便
- React的文檔感受比較注重實操,對基礎的講解較少,在教程部分就會教你如何實現一個井字棋的(這一點是比較友好的)
組件
這兩個框架都是推薦把頁面組件化的,可是二者之間對於組件也有各自的不一樣
生命週期
Vue
- 主要分爲8個階段:
beforeCreate
created (在這個階段就能夠首次拿到data中定義的數據)
beforeMount
mounted(在這個階段Dom樹渲染完畢可訪問Dom結構)
beforeUpdate
updated
beforeDestroy
destroyed
React
- 主要分爲3個階段:
Mounting初始化 -> Updating運行中 -> Unmounting銷燬
-
生命週期中的方法react
- 【react 16.0以後已移除】 componentWillMount():在render()以前執行,因此在這個階段的setState()不會從新渲染;一般用constructor()代替
- render():在componentWillMount()以後執行
- componentDidMount():在render()以後執行,因此在這個階段的setState()會從新渲染;這裏能夠對DOM進行操做
- 【react 16.0以後已移除】 componentWillReceiveProps(nextProps):當已掛載組件收到新的props時執行,但有可能props傳入時沒有發生改變但仍然從新渲染了,若是想要避免這種狀況能夠在傳入新的props時比較一下新舊props之間是否發生變化;這裏須要注意一下,若是隻是調用了setState()的話是不會觸發這個方法的,只有props發生改變或者沒有發生改變時纔會觸發這個方法
- shouldComponentUpdate(nextProps,nextState):在接收到新的props或者state時肯定是否發生從新渲染,默認值爲true;在首次渲染時不會觸發這個方法
- 【react 16.0以後已移除】 componentWillUpdate(nextProps,nextState):在shouldComponentUpdate()以後,render()以前觸發;在組件初始化時不會被觸發
- componentDidUpdate(prevProps,prevState):在componentWillUpdate(nextProps,nextState)以後調用;在組件初始化時不會被觸發,此時能夠對DOM進行操做
組件形式
Vue Template
- Vue組件的編寫結構分爲三部分,分別是 template(HTML) script(JS) style(CSS)
- 將三者獨立開來,更好的注重每一部分的開發
- CSS:Vue默認是在單文件組件中在<script scoped></script>標籤裏寫CSS樣式,咱們能夠經過在
<script scoped></script>
標籤中寫上scoped
,這樣這部分樣式就只用來控制該組件的樣式,而不會影響到其餘組件。
-
JS:模版部分使用數據:須要將變量放在雙大括號內{{}}
vue-router
<template>
<!-- HTML Code -->
<div>{{name}}</div>
</template>
<script>
export default{
name: 'NewComponent',
data() {
return {
name: 'xx'
}
}
}
</script>
<style scoped>
/* CSS Code */
</style>
React JSX
- React支持Class組件和Function組件
- React組件使用render渲染函數,能夠用JavaScript來構建視圖頁面,常包含了大量的邏輯
- CSS:React是經過使用className字段來設置樣式,通常都是引入外部的css,且通常都會使用less預編譯
-
JS:將變量放在{}
內vuex
// class組件
class Template extends React.Component{
render() {
return (
<div className="shopping-list">
<h1>Shopping List for {this.props.name}</h1>
</div>
);
}
}
// function組件
function NewComponent() {
const [name, setName] = useState('');
return (<div>{name}</div>);
}
數據管理
Vue對象屬性
React狀態管理
class組件state
function組件hooks
數據流
單向數據流中的
單向:我理解的是父級數據的更新會向下流動到子組件中,可是反過來則不行,這樣能夠防止從子組件意外改變父級組件的狀態
Vue雙向數據綁定
vue仍然是單向數據流
表現形式
- 使用
v-model
-
通常有兩種使用情景:app
-
v-model
實質爲語法糖
<input v-model="message" />
// 等價於:
<input
v-bind:value="message" // 與data中聲明的數據進行綁定
v-on:input="message=$event.target.value" // 監聽輸入框中值的變化
/>
// 實現原理
// 修改AST元素,給el添加一個prop,至關於動態綁定了value
addProp(el,'value',`(${value})`);
// 添加事件處理,至關於給input綁定了input事件
addHandler(el,event,code,null,true);
實現原理
- vue使用的是發佈者訂閱者的模式+數據劫持的方式來實現的,在組件中咱們定義data時,vue會遍歷這個對象,經過
Object.defineProperty()
給每個值都添加getter
和setter
方法,而後每個組件都有一個watcher來監聽數據的變化,當數據發生變化的時候,即觸發setter
時,就會發布消息給訂閱者,觸發相應的監聽回調
Vue2.0的缺陷
- 不具有監聽數組的能力,須要從新定義數組的原型來達到響應式
- 沒法檢測到對象屬性的添加和刪除
- 只能劫持對象的屬性(假如須要對每一個對象的每一個屬性進行遍歷,若是屬性值也是對象那麼須要深度遍歷,顯然能劫持一個完整的對象是更好的選擇)
解決方法:Vue.set() || this.$set()
- 若是在實例建立以後添加新的屬性到實例上,它不會觸發視圖更新,由於此時添加的屬性並無綁定上
getter
、setter
,所以這個屬性是非響應式。若是咱們想要把這個屬性變成響應式的話,能夠經過Vue.set()
或者this.$set()
這兩種方式添加新的屬性
- 除了添加新的屬性之外,改變數組的一些屬性也不會使得視圖更新,
- 利用索引直接設置數組的某一項
arr[1] = 10
- 直接修改數組的大小
arr.length = 10
- 對於數組除了能夠經過
Vue.set()
、this.$set()
這兩種方式,還可使用數組的一些API來觸發更新,如splice()
、concat()
等會修改原始數組的API
Vue3.0的改進
-
使用ES6中的proxy框架
- 能夠劫持到整個對象而非屬性,並返回一個新的對象
- 能夠監聽到數組的變化
React單向數據流
特色
- React採用單向數據流的形式,即它只接收數據,但不改變數據,只監聽數據的改變;當數據發生變化的時候,它會接收使用新的數據,從新進行渲染。
- 我以爲單向數據流最大的好處的話,是當多個組件都要對同一個值進行操做的時候,因爲數據只有一份,所以可以保持它的一致性。
狀態管理器
什麼狀況下咱們要使用狀態管理器呢?
通常是當多個組件須要共同維護一些數據,使用傳值的方式會十分複雜,於是咱們能夠把這些須要共同維護的數據提取出來,放在store中共同維護,這樣就能夠保證數據的一致性
Vue
Vuex
- 單一數據源:只有一個store
- mutation(同步操做):修改state只能經過mutation的方式,須要經過store.commit()來提交mutation
- action(異步操做):action裏面能夠包含多個mutation,最後也是要經過store.commit()來觸發mutation,action須要經過store.dispatch()來觸發
- model:引入來模塊化,就是想要把store進行拆分,每一個 Module 有本身的 state、mutation、action、getter,能夠各自維護,最後再把每一個store組合起來,不違背Vuex的單一數據源
React
Redux
- 單一數據源:只有一個store
- state是隻讀的:須要經過reducer純函數返回一個新的state
- 單向數據流
- 使用的是不可變數據,每次更新都是使用新的state來替換舊的state
Mobx-React
- 能夠有多個store
- store中的state能夠直接修改
@observable // 咱們要在須要觀察的數據加上@observable
current: number = 1;
total: number = 0;
@action // 將修改被觀測變量的行爲放在action中
updateCurrent(current: number) {
this.current = current;
}
// 對於異步操做,action沒法影響當前函數調用的異步操做,可使用runInAction來解決
async getList() {
// some code
runInAction(() => {
this.total = res.total;
});
}
路由
Vue-Router
vue是單頁面應用,頁面跳轉不會發送請求
hash模式
表層原理
- 使用hash來模擬一個完整的URL,因此當URL發生改變的時候,不會從新加載
- hash出如今URL中,但並不會包含到http請求中,所以當hash值發生變化的時候,並不會引發頁面的請求
- 當#後的值發生變化的時候,會向瀏覽器的歷史瀏覽增長一個記錄,當點擊後退按鈕時,會彈出,以此來實現頁面的跳轉
- 經過onhashchange事件監聽hash值的變化
history模式
// 像這樣
http://localhost:8080/home/center
表層原理
- history模式主要使用的是HTML5中提供的API
history.pushState()
和history.replaceState()
來實現
- 須要注意的是,history模式不怕前進,不怕後退,就怕刷新
- history模式下若是刷新頁面的話,可能會返回404,由於當刷新頁面的時候,會真實的向服務端發送請求,但若是此時該頁面沒有在服務端配置過的話就會返回404,所以須要服務端進行重定向,可使用Nginx,使用try_file和rewrite實現重定向
React-Router(待完善)
BrowserRouter
HashRouter
腳手架(待補充)
Vue-Cli
Create-React-App
單元測試(待補充)
從Vue到React
- 雖然我是先學習和使用Vue的,可是因爲之前學習過Java等一些面向對象的語言,因此從Vue到React的過渡並無不適應,反而以爲很熟悉;並且React使用JS來構建頁面,能夠在裏面寫邏輯,我以爲很是安逸呀。
- 但其實不論是哪種框架,適合這個項目的框架那它就是好框架,不一樣的框架有不一樣的特殊點,若是這個特殊點和項目的要求想契合的話,那就是它了!