前端面試題(框架部分)


Vue:
一、MVVM模式與MVC模式的區別
MVVM即Model-View-ViewModel。
它是將“數據模型數據雙向綁定”的思想作為核心,因此在View和Model之間沒有聯系,通過ViewModel進行交互,而且Model和ViewModel之間的交互是雙向的,因此視圖的數據的變化會同時修改數據源,而數據源數據的變化也會立即反應到View上。
Vue是以數據為驅動的,Vue自身將DOM和數據進行綁定,一旦創建綁定,DOM和數據將保持同步,每當數據發生變化,DOM會跟着變化。 ViewModel是Vue的核心,它是Vue的一個實例。Vue實例時作用域某個HTML元素上的,這個HTML元素可以是body,也可以是某個id所指代的元素。 DOM Listeners和Data Bindings是實現雙向綁定的關鍵。DOM Listeners監聽頁面所有View層DOM元素的變化,當發生變化,Model層的數據隨之變化;Data Bindings監聽Model層的數據,當數據發生變化,View層的DOM元素隨之變化。
MVC即Model-View-Controller
MVC是比較直觀的架構模式,用戶操作->View(負責接收用戶的輸入操作)->Controller(業務邏輯處理)->Model(數據持久化)->View(將結果反饋給View)。
二、v-show與v-if的區別
條件渲染指令,與v-if不同的是,無論v-show的值為true或false,元素都會存在於HTML代碼中;而只有當v-if的值為true,元素才會存在於HTML代碼中。v-show指令只是設置了元素CSS的style值
三、如何讓css只在當前組件中起作用

在每一個vue組件中都可以定義各自的css,js,如果希望組件內寫的css只對當前組件起作用,只需要在style中寫入scoped,即:
<style scoped></style>
四、指令keep-alive
在vue-router寫着keep-alive,keep-alive的含義: 如果把切換出去的組件保留在內存中,可以保留它的狀態或避免重新渲染。為此可以添加一個keep-alive指令
<component :is='curremtView' keep-alive></component>
五、Vue.js與其他框架的區別?
1.與AngularJS的區別
相同點:
都支持指令:內置指令和自定義指令。
都支持過濾器:內置過濾器和自定義過濾器。
都支持雙向數據綁定。
都不支持低端瀏覽器。
不同點:
(1).AngularJS的學習成本高,比如增加了Dependency Injection特性,而Vue.js本身提供的API都比較簡單、直觀。
(2).在性能上,AngularJS依賴對數據做臟檢查,所以Watcher越多越慢。
Vue.js使用基於依賴追蹤的觀察並且使用異步隊列更新。所有的數據都是獨立觸發的。
(3).vue中數據放在data對象里面,angular數據綁定在$scope上面
(4).vue有組件化概念,angular中沒有
2.與React的區別
相同點:
React采用特殊的JSX語法,Vue.js在組件開發中也推崇編寫.vue特殊文件格式,對文件內容都有一些約定,兩者都需要編譯后使用。
中心思想相同:一切都是組件,組件實例之間可以嵌套。
都提供合理的鈎子函數,可以讓開發者定制化地去處理需求。
都不內置列數AJAX,Route等功能到核心包,而是以插件的方式加載。
在組件開發中都支持mixins的特性。
不同點:
React依賴Virtual DOM,而Vue.js使用的是DOM模板。React采用的Virtual DOM會對渲染出來的結果做臟檢查。
Vue.js在模板中提供了指令,過濾器等,可以非常方便,快捷地操作DOM。
參考:http://blog.csdn.net/haoshidai/article/details/52346865
六、Vue的雙向數據綁定原理是什么?
vue.js 是采用數據劫持結合發布者-訂閱者模式的方式,通過Object.defineProperty()來劫持各個屬性的setter,getter,在數據變動時發布消息給訂閱者,觸發相應的監聽回調。

具體步驟:

第一步:需要observe的數據對象進行遞歸遍歷,包括子屬性對象的屬性,都加上 setter和getter
這樣的話,給這個對象的某個值賦值,就會觸發setter,那么就能監聽到了數據變化

第二步:compile解析模板指令,將模板中的變量替換成數據,然后初始化渲染頁面視圖,並將每個指令對應的節點綁定更新函數,添加監聽數據的訂閱者,一旦數據有變動,收到通知,更新視圖

第三步:Watcher訂閱者是Observer和Compile之間通信的橋梁,主要做的事情是:
1、在自身實例化時往屬性訂閱器(dep)里面添加自己
2、自身必須有一個update()方法
3、待屬性變動dep.notice()通知時,能調用自身的update()方法,並觸發Compile中綁定的回調,則功成身退。
七、vue如何實現父子組件通信,以及非父子組件通信?
1、父子:
使用props:
props監聽父組件傳遞過來的信息
傳遞過來后,可直接引用,就如已經傳遞過來數據塞到data
使用$refs:
this.$refs.XXX
2、子父:
自定義事件:
父組件可以在使用子組件的地方直接用 v-on 來監聽子組件觸發的事件
子組件$emit()觸發,父組件$on()監聽
使用$parent:
this.$parent.XXX
3、非父子:
簡單場景用bus,復雜場景用vuex

<div id="app4">
<display></display>
<increment></increment>
</div>
<script>
var bus = new Vue();
Vue.component('increment', {
template: `<button @click="add">+</button>`,
data: function () {
return {count: 0}
},
methods: {
add: function () {
bus.$emit('inc', this.count+=1)
}
}
});
Vue.component('display', {
template: `<span>Clicked: <mark>{{c}}</mark> times</span>`,
data: function () {
return {c: 0}
},
created: function () {
var self=this;
// bus.$on('inc', function (num) {
// self.c = num
// });
bus.$on('inc', (num) =>
this.c = num
);
}
});
vm = new Vue({
el: "#app4",
})
</script>

八、vue響應式原理?
工作原理是當我們把一個普通的JavaScript對象傳給Vue 實例的data選項的時候,Vue會遍歷此對象的所有屬性,並使用Object.definePropert把這些屬性全部轉化為getter/setter。(Object.definePropert是僅ES5支持,且沒有墊片腳本的特性,因此Vue不支持IE8及更低版本瀏覽器。)用戶看不到getter/setter,但是在內部它們讓Vue追蹤依賴,在屬性被訪問和修改時通知變化。每個組件實例都有相應的watcher實例對象,它會在組件渲染的過程中把屬性記錄為依賴,之后當依賴項的setter被調用時,會通知watcher重新計算,從而使它關聯的組件得以更新。
九、vue-router相關
1、vue-router實現原理?
單頁面應用(SPA)的核心之一是: 更新視圖而不重新請求頁面,
實現這一點主要是兩種方式:
1.Hash: 通過改變hash值
2.History: 利用history對象新特性(詳情可出門左拐見: http://www.cnblogs.com/yanze/p/7641774.html)

而在vue-router中,它提供mode參數來決定采用哪一種方式,選擇流程如下:
默認Hash-->如果瀏覽器支持History新特性改用History-->如果不在瀏覽器環境則使用abstract

基本方法分析:
Hash
1.push()
功能: 設置新的路由添加歷史記錄並更新視圖,常用情況是直接點擊切換視圖
調用流程:
1 $router.push() //顯式調用方法
2 HashHistory.push() //根據hash模式調用,設置hash並添加到瀏覽器歷史記錄(window.location.hash= XXX)
3 History.transitionTo() //開始更新
4 History.updateRoute() //更新路由
5 {app._route= route}
6 vm.render() //更新視圖

2.replace
功能: 替換當前路由並更新視圖,常用情況是地址欄直接輸入新地址
流程與push基本一致
但流程2變為替換當前hash (window.location.replace= XXX)不懂此方法的可見: http://www.w3school.com.cn/jsref/met_loc_replace.asp

3.監聽地址欄變化
在setupListeners中監聽hash變化(window.onhashchange)並調用replace

History
1.push
與hash模式類似,只是將window.hash改為history.pushState
2.replace
與hash模式類似,只是將window.replace改為history.replaceState
3.監聽地址變化
在HTML5History的構造函數中監聽popState(window.onpopstate)

兩種模式對比
History模式的優點:
1.History模式的地址欄更美觀。。。
2.History模式的pushState、replaceState參數中的新URL可為同源的任意URL(可為不同的html文件),而hash只能是同一文檔
3.History模式的pushState、replaceState參數中的state可為js對象,能攜帶更多數據
4.History模式的pushState、replaceState參數中的title能攜帶字符串數據(當然,部分瀏覽器,例如firefox不支持title,一般title設為null,不建議使用)
缺點:
對於單頁面應用來說,理想的場景是僅僅在進入應用時加載頁面(例如index.html),后續的網絡操作靠ajax完成,
而不會重新請求頁面。
但當用戶直接在用戶欄輸入地址時則會重新請求,當地址帶有參數時兩者情況不一樣
Hash 例如: xxx.com/#/id=5 HTTP請求不會包含后面的hash值,所以請求的仍然是 xxx.com,沒有問題
History 例如: xxx.com/id=5 這時請求的便是xxx.com/id=5,如后端沒有配置對應id=XXX的路由處理,則會返回404錯誤。
2、怎么定義vue-router的動態路由?怎么獲取傳過來的動態參數?
在router目錄下的index.js文件中,對path屬性加上/:id。 使用router對象的params.id
3、vue-router有哪幾種導航鈎子?
三種,一種是全局導航鈎子:router.beforeEach(to,from,next),作用:跳轉前進行判斷攔截。第二種:組件內的鈎子;第三種:單獨路由獨享組件
4、vue-router是什么?它有哪些組件?
vue用來寫路由一個插件。router-link、router-view
5、導航鈎子有哪些?它們有哪些參數?
導航鈎子有:a/全局鈎子和組件內獨享的鈎子。b/beforeRouteEnter、afterEnter、beforeRouterUpdate、beforeRouteLeave
參數:有to(去的那個路由)、from(離開的路由)、next(一定要用這個函數才能去到下一個路由,如果不用就攔截)最常用就這幾種
十、scss是什么?安裝使用的步驟是?有哪幾大特性?
預處理css,把css當前函數編寫,定義變量,嵌套。 先裝css-loader、node-loader、sass-loader等加載器模塊,在webpack-base.config.js配置文件中加多一個拓展:extenstion,再加多一個模塊:module里面test、loader
有哪幾大特性:
1、可以用變量,例如($變量名稱=值);
2、可以用混合器,例如()
3、可以嵌套
十一、vuex相關
1、vuex是什么?怎么使用?哪種功能場景使用它?
vue框架中狀態管理。
在main.js引入store,注入。新建了一個目錄store,….. export 。
應用級的狀態集中放在store中; 改變狀態的方式是提交mutations,這是個同步的事物; 異步邏輯應該封裝在action中。
場景有:單頁應用中,組件之間的狀態。音樂播放、登錄狀態、加入購物車
2、vuex有哪幾種屬性?
有五種,分別是 State、 Getter、Mutation 、Action、 Module

3、vuex的State特性是?
一、Vuex就是一個倉庫,倉庫里面放了很多對象。其中state就是數據源存放地,對應於與一般Vue對象里面的data
二、state里面存放的數據是響應式的,Vue組件從store中讀取數據,若是store中的數據發生改變,依賴這個數據的組件也會發生更新
三、它通過mapState把全局的 state 和 getters 映射到當前組件的 computed 計算屬性中

4、vuex的Getter特性是?
一、getters 可以對State進行計算操作,它就是Store的計算屬性
二、 雖然在組件內也可以做計算屬性,但是getters 可以在多組件之間復用
三、 如果一個狀態只在一個組件內使用,是可以不用getters

5、vuex的Mutation特性是?
一、Action 類似於 mutation,不同在於:
二、Action 提交的是 mutation,而不是直接變更狀態。
三、Action 可以包含任意異步操作

6、Vue.js中ajax請求代碼應該寫在組件的methods中還是vuex的actions中?
一、如果請求來的數據是不是要被其他組件公用,僅僅在請求的組件內使用,就不需要放入vuex 的state里。
二、如果被其他地方復用,這個很大幾率上是需要的,如果需要,請將請求放入action里,方便復用,並包裝成promise返回,在調用處用async await處理返回的數據。如果不要復用這個請求,那么直接寫在vue文件里很方便。

7、不用Vuex會帶來什么問題?
一、可維護性會下降,你要想修改數據,你得維護三個地方
二、可讀性會下降,因為一個組件里的數據,你根本就看不出來是從哪來的
三、增加耦合,大量的上傳派發,會讓耦合性大大的增加,本來Vue用Component就是為了減少耦合,現在這么用,和組件化的初衷相背。
十二、生命周期相關
1、請詳細說下你對vue生命周期的理解?
總共分為8個階段創建前/后,載入前/后,更新前/后,銷毀前/后。
創建前/后: 在beforeCreated階段,vue實例的掛載元素$el和數據對象data都為undefined,還未初始化。在created階段,vue實例的數據對象data有了,$el還沒有。
載入前/后:在beforeMount階段,vue實例的$el和data都初始化了,但還是掛載之前為虛擬的dom節點,data.message還未替換。在mounted階段,vue實例掛載完成,data.message成功渲染。
更新前/后:當data變化時,會觸發beforeUpdate和updated方法。
銷毀前/后:在執行destroy方法后,對data的改變不會再觸發周期函數,說明此時vue實例已經解除了事件監聽以及和dom的綁定,但是dom結構依然存在
2、什么是vue生命周期?
Vue 實例從創建到銷毀的過程,就是生命周期。也就是從開始創建、初始化數據、編譯模板、掛載Dom→渲染、更新→渲染、卸載等一系列過程,我們稱這是 Vue 的生命周期。
3、vue生命周期的作用是什么?
它的生命周期中有多個事件鈎子,讓我們在控制整個Vue實例的過程時更容易形成好的邏輯。

4、vue生命周期總共有幾個階段?
它可以總共分為8個階段:創建前/后, 載入前/后,更新前/后,銷毀前/銷毀后

5、第一次頁面加載會觸發哪幾個鈎子?
第一次頁面加載時會觸發 beforeCreate, created, beforeMount, mounted 這幾個鈎子

6、DOM 渲染在 哪個周期中就已經完成?
DOM 渲染在 mounted 中就已經完成了。

7、簡單描述每個周期具體適合哪些場景?
答:生命周期鈎子的一些使用方法: beforecreate : 可以在這加個loading事件,在加載實例時觸發 created : 初始化完成時的事件寫在這里,如在這結束loading事件,異步請求也適宜在這里調用 mounted : 掛載元素,獲取到DOM節點 updated : 如果對數據統一處理,在這里寫上相應函數 beforeDestroy : 可以做一個確認停止事件的確認框 nextTick : 更新數據后立即操作dom
十三、請說下封裝 vue 組件的過程?
首先,組件可以提升整個項目的開發效率。能夠把頁面抽象成多個相對獨立的模塊,解決了我們傳統項目開發:效率低、難維護、復用性等問題。
然后,使用Vue.extend方法創建一個組件,然后使用Vue.component方法注冊組件。子組件需要數據,可以在props中接受定義。而子組件修改好數據后,想把數據傳遞給父組件。可以采用emit方法。
十四、vue-loader是什么?使用它的用途有哪些?
解析.vue文件的一個加載器,跟template/js/style轉換成js模塊。
用途:js可以寫es6、style樣式可以scss或less、template可以加jade等
十五、你對Vue.js的template編譯的理解?
簡而言之,就是先轉化成AST樹,再得到的render函數返回VNode(Vue的虛擬DOM節點)
詳情步驟:
首先,通過compile編譯器把template編譯成AST語法樹(abstract syntax tree 即 源代碼的抽象語法結構的樹狀表現形式),compile是createCompiler的返回值,createCompiler是用以創建編譯器的。另外compile還負責合並option。
然后,AST會經過generate(將AST語法樹轉化成render funtion字符串的過程)得到render函數,render的返回值是VNode,VNode是Vue的虛擬DOM節點,里面有(標簽名、子節點、文本等等)

React:
一、當你調用setState的時候,發生了什么?
當調用 setState 時,React會做的第一件事情是將傳遞給 setState 的對象合並到組件的當前狀態。這將啟動一個稱為和解(reconciliation)的過程。和解(reconciliation)的最終目標是以最有效的方式,根據這個新的狀態來更新UI。 為此,React將構建一個新的 React 元素樹(您可以將其視為 UI 的對象表示)。
一旦有了這個樹,為了弄清 UI 如何響應新的狀態而改變,React 會將這個新樹與上一個元素樹相比較( diff )。
通過這樣做, React 將會知道發生的確切變化,並且通過了解發生什么變化,只需在絕對必要的情況下進行更新即可最小化 UI 的占用空間。
二、在 React 當中 Element 和 Component 有何區別?
簡單地說,一個 React element 描述了你想在屏幕上看到什么。換個說法就是,一個 React element 是一些 UI 的對象表示。
一個 React Component 是一個函數或一個類,它可以接受輸入並返回一個 React element t(通常是通過 JSX ,它被轉化成一個 createElement 調用)。
三、什么時候在功能組件( Class Component )上使用類組件( Functional Component )?
如果您的組件具有狀態( state )或生命周期方法,請使用 Class 組件。否則,使用功能組件
四、什么是 React 的 refs ,為什么它們很重要?
refs就像是一個逃生艙口,允許您直接訪問DOM元素或組件實例。為了使用它們,您可以向組件添加一個 ref 屬性,該屬性的值是一個回調函數,它將接收底層的 DOM 元素或組件的已掛接實例,作為其第一個參數。

class UnControlledForm extends Component {
handleSubmit = () => {
console.log("Input Value: ", this.input.value)
}
render () {
return (
<form onSubmit={this.handleSubmit}>
<input
type='text'
ref={(input) => this.input = input} />
<button type='submit'>Submit</button>
</form>
)
}
}

以上注意到我們的輸入字段有一個 ref 屬性,其值是一個函數。該函數接收我們然后放在實例上的實際的 DOM 元素,以便在 handleSubmit 函數內部訪問它。經常誤解的是,您需要使用類組件才能使用 ref ,但 ref 也可以通過利用 JavaScript 中的 閉包 與 功能組件( functional components )一起使用。

function CustomForm ({handleSubmit}) {
let inputElement
return (
<form onSubmit={() => handleSubmit(inputElement.value)}>
<input
type='text'
ref={(input) => inputElement = input} />
<button type='submit'>Submit</button>
</form>
)
}

五、React 中的keys是什么,為什么它們很重要?
keys是什么幫助 React 跟蹤哪些項目已更改、添加或從列表中刪除。

return (
<ul>
{this.state.todoItems.map(({task, uid}) => {
return <li key={uid}>{task}</li>
})}
</ul>
)
}

每個 keys 在兄弟元素之間是獨一無二的。我們已經談過幾次關於和解(reconciliation)的過程,而且這個和解過程(reconciliation)中的一部分正在執行一個新的元素樹與最前一個的差異。keys 使處理列表時更加高效,因為 React 可以使用子元素上的 keys 快速知道元素是新的還是在比較樹時才被移動。

而且 keys 不僅使這個過程更有效率,而且沒有 keys ,React 不知道哪個本地狀態對應於移動中的哪個項目。所以當你 map 的時候,不要忽略了 keys 。
六、受控組件( controlled component )與不受控制的組件( uncontrolled component )有什么區別?
React 的很大一部分是這樣的想法,即組件負責控制和管理自己的狀態。

當我們將 native HTML 表單元素( input, select, textarea 等)投入到組合中時會發生什么?我們是否應該使用 React 作為“單一的真理來源”,就像我們習慣使用React一樣? 或者我們是否允許表單數據存在 DOM 中,就像我們習慣使用HTML表單元素一樣? 這兩個問題是受控(controlled) VS 不受控制(uncontrolled)組件的核心。

受控組件是React控制的組件,也是表單數據的唯一真理來源。

如下所示, username 不存在於 DOM 中,而是以我們的組件狀態存在。每當我們想要更新 username 時,我們就像以前一樣調用setState。

class ControlledForm extends Component {
state = {
username: ''
}
updateUsername = (e) => {
this.setState({
username: e.target.value,
})
}
handleSubmit = () => {}
render () {
return (
<form onSubmit={this.handleSubmit}>
<input
type='text'
value={this.state.username}
onChange={this.updateUsername} />
<button type='submit'>Submit</button>
</form>
)
}
}

不受控制( uncontrolled component )的組件是您的表單數據由 DOM 處理,而不是您的 React 組件。

我們使用 refs 來完成這個。

class UnControlledForm extends Component {
handleSubmit = () => {
console.log("Input Value: ", this.input.value)
}
render () {
return (
<form onSubmit={this.handleSubmit}>
<input
type='text'
ref={(input) => this.input = input} />
<button type='submit'>Submit</button>
</form>
)
}
}

雖然不受控制的組件通常更容易實現,因為您只需使用引用從DOM獲取值,但是通常建議您通過不受控制的組件來支持受控組件。

主要原因是受控組件 支持即時字段驗證 ,允許您有條件地禁用/啟用按鈕,強制輸入格式
七、在哪個生命周期事件中你會發出 AJAX 請求,為什么?

AJAX 請求應該在 componentDidMount 生命周期事件中。 有幾個原因:

Fiber,是下一次實施React的和解算法,將有能力根據需要啟動和停止渲染,以獲得性能優勢。其中一個取舍之一是 componentWillMount ,而在其他的生命周期事件中出發 AJAX 請求,將是具有 “非確定性的”。 這意味着 React 可以在需要時感覺到不同的時間開始調用 componentWillMount。這顯然是AJAX請求的不好的方式。
-您不能保證在組件掛載之前,AJAX請求將無法 resolve。如果這樣做,那意味着你會嘗試在一個未掛載的組件上設置 StState,這不僅不會起作用,反而會對你大喊大叫。 在 componentDidMount 中執行 AJAX 將保證至少有一個要更新的組件。
八、shouldComponentUpdate 應該做什么,為什么它很重要?
在生命周期方法 shouldComponentUpdate 中,允許我們選擇退出某些組件(和他們的子組件)的 reconciliation 過程。

我們為什么要這樣做?

如上所述,“和解( reconciliation )的最終目標是以最有效的方式,根據新的狀態更新用戶界面”。如果我們知道我們的用戶界面(UI)的某一部分不會改變,那么沒有理由讓 React 很麻煩地試圖去弄清楚它是否應該渲染。通過從 shouldComponentUpdate 返回 false,React 將假定當前組件及其所有子組件將保持與當前組件相同。
九、您如何告訴React 構建(build)生產模式,該做什么?
通常,您將使用Webpack的 DefinePlugin 方法將 NODE_ENV 設置為 production。這將剝離像 propType 驗證和額外的警告。除此之外,還有一個好主意,可以減少你的代碼,因為React使用 Uglify 的 dead-code 來消除開發代碼和注釋,這將大大減少你的包的大小。

為什么要使用 React.Children.map(props.children,()=>) 而不是 props.children.map(()=>)

因為不能保證props.children將是一個數組。

以此代碼為例,

<Parent>
<h1>Welcome.</h1>
</Parent>
在父組件內部,如果我們嘗試使用 props.children.map 映射孩子,則會拋出錯誤,因為 props.children 是一個對象,而不是一個數組。

如果有多個子元素,React 只會使props.children成為一個數組。就像下面這樣:

<Parent>
<h1>Welcome.</h1>
<h2>props.children will now be an array</h2>
</Parent>
這就是為什么你喜歡 React.Children.map ,因為它的實現考慮到 props.children 可能是一個數組或一個對象。
十、概述下 React 中的事件處理邏輯

為了解決跨瀏覽器兼容性問題,React 會將瀏覽器原生事件(Browser Native Event)封裝為合成事件(SyntheticEvent)傳入設置的事件處理器中。這里的合成事件提供了與原生事件相同的接口,不過它們屏蔽了底層瀏覽器的細節差異,保證了行為的一致性。另外有意思的是,React 並沒有直接將事件附着到子元素上,而是以單一事件監聽器的方式將所有的事件發送到頂層進行處理。這樣 React 在更新 DOM 的時候就不需要考慮如何去處理附着在 DOM 上的事件監聽器,最終達到優化性能的目的。
十一、createElement 與 cloneElement 的區別是什么?
createElement 函數是 JSX 編譯之后使用的創建 React Element 的函數,而 cloneElement 則是用於復制某個元素並傳入新的 Props。
十二、傳入 setState 函數的第二個參數的作用是什么?
該函數會在setState函數調用完成並且組件開始重渲染的時候被調用,我們可以用該函數來監聽渲染是否完成:

this.setState(
{ username: 'tylermcginnis33' },
() => console.log('setState has finished and the component has re-rendered.')
)
十三、react的優缺點
優點:
可以通過函數式方法描述視圖組件(好處:相同的輸入會得到同樣的渲染結果,不會有副作用;組件不會被實例化,整體渲染性能得到提升)集成虛擬DOM(性能好)
單向數據流(好處是更容易追蹤數據變化排查問題
一切都是component:代碼更加模塊化,重用代碼更容易,可維護性高
大量擁抱 es6 新特性
jsx
缺點:
jsx的一個問題是,渲染函數常常包含大量邏輯,最終看着更像是程序片段,而不是視覺呈現。后期如果發生需求更改,維護起來工作量將是巨大的
大而全,上手有難度
十四、React:組件的生命周期
實例化
首次實例化

getDefaultProps
getInitialState
componentWillMount
render
componentDidMount
實例化完成后的更新

getInitialState
componentWillMount
render
componentDidMount
存在期
組件已存在時的狀態改變

componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate
銷毀&清理期
componentWillUnmount
說明
生命周期共提供了10個不同的API。

1.getDefaultProps

作用於組件類,只調用一次,返回對象用於設置默認的props,對於引用值,會在實例中共享。

2.getInitialState

作用於組件的實例,在實例創建時調用一次,用於初始化每個實例的state,此時可以訪問this.props。

3.componentWillMount

在完成首次渲染之前調用,此時仍可以修改組件的state。

4.render

必選的方法,創建虛擬DOM,該方法具有特殊的規則:

只能通過this.props和this.state訪問數據
可以返回null、false或任何React組件
只能出現一個頂級組件(不能返回數組)
不能改變組件的狀態
不能修改DOM的輸出
5.componentDidMount

真實的DOM被渲染出來后調用,在該方法中可通過this.getDOMNode()訪問到真實的DOM元素。此時已可以使用其他類庫來操作這個DOM。

在服務端中,該方法不會被調用。

6.componentWillReceiveProps

組件接收到新的props時調用,並將其作為參數nextProps使用,此時可以更改組件props及state。

componentWillReceiveProps: function(nextProps) {
if (nextProps.bool) {
this.setState({
bool: true
});
}
}
7.shouldComponentUpdate

組件是否應當渲染新的props或state,返回false表示跳過后續的生命周期方法,通常不需要使用以避免出現bug。在出現應用的瓶頸時,可通過該方法進行適當的優化。

在首次渲染期間或者調用了forceUpdate方法后,該方法不會被調用

8.componentWillUpdate

接收到新的props或者state后,進行渲染之前調用,此時不允許更新props或state。

9.componentDidUpdate

完成渲染新的props或者state后調用,此時可以訪問到新的DOM元素。

10.componentWillUnmount

組件被移除之前被調用,可以用於做一些清理工作,在componentDidMount方法中添加的所有任務都需要在該方法中撤銷,比如創建的定時器或添加的事件監聽器。
十五、React組件通信
1、父組件向子組件通信:使用 props
這是最簡單也是最常用的一種通信方式:父組件通過向子組件傳遞 props,子組件得到 props 后進行相應的處理。
2、子組件向父組件通信:使用 props 回調
利用回調函數,可以實現子組件向父組件通信:父組件將一個函數作為 props 傳遞給子組件,子組件調用該回調函數,便可以向父組件通信。
3、跨級組件間通信:使用 context 對象
所謂跨級組件通信,就是父組件向子組件的子組件通信,向更深層的子組件通信。跨級組件通信可以采用下面兩種方式:

中間組件層層傳遞 props
使用 context 對象

對於第一種方式,如果父組件結構較深,那么中間的每一層組件都要去傳遞 props,增加了復雜度,並且這些 props 並不是這些中間組件自己所需要的。不過這種方式也是可行的,當組件層次在三層以內可以采用這種方式,當組件嵌套過深時,采用這種方式就需要斟酌了。
使用 context 是另一種可行的方式,context 相當於一個全局變量,是一個大容器,我們可以把要通信的內容放在這個容器中,這樣一來,不管嵌套有多深,都可以隨意取用。

使用 context 也很簡單,需要滿足兩個條件:

上級組件要聲明自己支持 context,並提供一個函數來返回相應的 context 對象
子組件要聲明自己需要使用 context

如果是父組件向子組件單向通信,可以使用變量,如果子組件想向父組件通信,同樣可以由父組件提供一個回調函數,供子組件調用,回傳參數。
在使用 context 時,有兩點需要注意:

父組件需要聲明自己支持 context,並提供 context 中屬性的 PropTypes
子組件需要聲明自己需要使用 context,並提供其需要使用的 context 屬性的 PropTypes
父組件需提供一個 getChildContext 函數,以返回一個初始的 context 對象
4、非嵌套組件間通信:使用事件訂閱
非嵌套組件,就是沒有任何包含關系的組件,包括兄弟組件以及不在同一個父級中的非兄弟組件。對於非嵌套組件,可以采用下面兩種方式:

利用二者共同父組件的 context 對象進行通信
使用自定義事件的方式

如果采用組件間共同的父級來進行中轉,會增加子組件和父組件之間的耦合度,如果組件層次較深的話,找到二者公共的父組件不是一件容易的事
自定義事件是典型的發布/訂閱模式,通過向事件對象上添加監聽器和觸發事件來實現組件間通信。
十六、react中prop和state的區別?
需要理解的是,props是一個父組件傳遞給子組件的數據流,這個數據流可以一直傳遞到子孫組件。而state代表的是一個組件內部自身的狀態(可以是父組件、子孫組件)。
十七、redux的原理?
Redux 把一個應用程序中,所有應用模塊之間需要共享訪問的數據,都應該放在 State 對象中。這個應用模塊可能是指 React Components,也可能是你自己訪問 AJAX API 的代理模塊,具體是什么並沒有一定的限制。State 以 “樹形” 的方式保存應用程序的不同部分的數據。這些數據可能來自於網絡調用、本地數據庫查詢、甚至包括當前某個 UI 組件的臨時執行狀態(只要是需要被不同模塊訪問)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM