周末加班,臨時整理些react有關(guān)的東西
1、immutable
一旦創(chuàng)建就不可修改的數(shù)據(jù)類型,對immutable對象的任何修改、添加或刪除操作都會返回一個新的immutable對象。其實現(xiàn)原理是Persistent Data Structure(持久化數(shù)據(jù)結(jié)構(gòu)),也就是使用舊數(shù)據(jù)創(chuàng)建新數(shù)據(jù)時要保證舊數(shù)據(jù)同時可用且不變。同時為了避免deepcopy(深拷貝)帶來的性能損耗,immutable使用了結(jié)構(gòu)共享Structural Sharing,即如果對象樹中的一個節(jié)點(diǎn)發(fā)生變化,只修改此節(jié)點(diǎn)和受影響的父節(jié)點(diǎn),其他節(jié)點(diǎn)則進(jìn)行共享。
Immutable優(yōu)點(diǎn)
- 降低 Mutable 帶來的復(fù)雜度
- 節(jié)省內(nèi)存空間
- 兩個對象對比,直接對比內(nèi)存地址即可,給react刷新優(yōu)化帶來非常大的便利
缺點(diǎn):容易與原生對象搞混
2、key的作用是什么
key是react用來追蹤節(jié)點(diǎn)被修改、添加或移除的標(biāo)識,react的diff算法會根據(jù)節(jié)點(diǎn)的key值判斷該節(jié)點(diǎn)是否需要刷新,以減少不必要的渲染。一般適用在列表組件的子項里,需保證同級元素key值的唯一性。在某些時候,甚至能直接改變組件的key值來達(dá)到重新渲染整個組件的目的。
3、調(diào)用setState發(fā)生了什么
setState一般用來更新數(shù)據(jù),重新渲染DOM元素。調(diào)用setState后,react會將參數(shù)對象合并到當(dāng)前狀態(tài),發(fā)起一個和解過程(reconciliation),以高效的方式生成一個新的元素樹,之后通過diff算法計算兩個元素樹的不同點(diǎn),進(jìn)行最小差異化渲染。
4、生命周期
constructor 初始化
componentWillMount
componentDidMount
shouldComponentUpdate
componentWillUnmount
render
componentWillReceiveProps
5、diff算法
1、把樹形結(jié)構(gòu)按層級分解,只比較同層級元素
2、按照key值來比較同級元素
3、react只匹配相同class的component,不同則直接刪除然后掛載新的節(jié)點(diǎn)
4、合并操作
5、選擇性的渲染
6、redux
三個原則
- 單一數(shù)據(jù)源
整個應(yīng)用的 state 被儲存在一棵 object tree 中,并且這個 object tree 只存在于唯一一個 store 中。
- State 是只讀的
唯一改變 state 的方法就是觸發(fā) action,action 是一個用于描述已發(fā)生事件的普通對象。
- 使用純函數(shù)來執(zhí)行修改
由用戶交互觸發(fā) -----> action ----(store.dispatch(action))---- > store ----(store調(diào)用reducer返回新的state)-----> reducer -----> view刷新
redux原理、同步異步如何實現(xiàn)、中間件的原理
中間件:react-logger、react-thunk。
異步action實現(xiàn):
在store.dispatch中傳入一個函數(shù)執(zhí)行,這個函數(shù)返回另一個函數(shù),參數(shù)有兩個,一個是dispatch、另一個則是getState,然后在這個函數(shù)中進(jìn)行異步操作,分別在異步開始、成功、失敗步驟中調(diào)用傳入的dispatch方法,傳入相應(yīng)的action;因為需要dispatch一個函數(shù),所以需要使用react-thunk配合。
applyMiddleware的實現(xiàn)原理:
使用柯里化函數(shù)來保存參數(shù),如果有中間件則會傳入createStore,在返回的函數(shù)里面構(gòu)建store,生成每個中間件都需要的dispatch和getState,再遍歷middlewares中間件數(shù)組,分別調(diào)用每個中間件一次。
第三個參數(shù)通過applyMiddleware添加中間件。
通過connect(mapStateToProps, mapDispatchToProps)(組件) 可以訪問到store里面特定的state和action,避免因為監(jiān)聽所有state變化造成性能問題。在mapDispatchToProps里面可以用bindActionCreators把dispatch和action creator綁定在一起,這樣就直接調(diào)用action creator函數(shù)就相當(dāng)于直接dispatch了
7、Hooks
Hook 是 React 16.8 的新增特性。它可以讓你在不編寫 class 的情況下使用 state 以及其他的 React 特性。
Hook 是一些可以讓你在函數(shù)組件里“鉤入” React state 及生命周期等特性的函數(shù)。Hook 不能在 class 組件中使用 —— 這使得你不使用 class 也能使用 React。
React內(nèi)置兩種hook:stateHook與effectHook。
import React, { useState } from 'react';
function Example() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
stateHook對function組件提供state支持,使函數(shù)組件可以使用state更新數(shù)據(jù)。useState參數(shù)只有一個,就是初始state,其返回一個數(shù)組包含變量名與更新函數(shù),這里使用了數(shù)組解構(gòu)獲取count與setCount,之后就可以直接使用setCount更新count的值。
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
// Similar to componentDidMount and componentDidUpdate:
useEffect(() => {
// Update the document title using the browser API
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
effectHook是每次組件更新都會調(diào)用的一個hook,你可以把 useEffect Hook 看做 componentDidMount,componentDidUpdate 和 componentWillUnmount 這三個函數(shù)的組合。也可以在useEffectHook中返回一個函數(shù),做一些掃尾工作,React 將會在執(zhí)行清除操作時調(diào)用它。
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
// Specify how to clean up after this effect:
return function cleanup() {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
userEffectHook還能傳入第二個參數(shù),已達(dá)到性能優(yōu)化的目的。
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // 僅在 count 更改時更新
第二個參數(shù)為一個數(shù)組,表示僅當(dāng)數(shù)組中的數(shù)據(jù)發(fā)生改變是,才執(zhí)行effect。
8、Context
避免繁瑣的props或者state的逐級傳遞,可以跨組件傳遞數(shù)據(jù)。通過createContext創(chuàng)建上下文對象,context對象主要是有provide(生產(chǎn)者)和consumer(消費(fèi)者)。使用provide包裹父組件,傳入value值;consumer包裹子組件,并使用function child的方式返回需要渲染的React節(jié)點(diǎn),完成context訂閱。Provider 及其內(nèi)部 consumer 組件都不受制于shouldComponentUpdate 函數(shù)。
<MyContext.Consumer>
{value => /* 基于 context 值進(jìn)行渲染*/}
</MyContext.Consumer>
9、refs
refs提供了一種訪問dom節(jié)點(diǎn)或react element的方法,我們可以使用它來播放視頻、管理焦點(diǎn)、觸發(fā)命令式動畫等操作。
10、webpack
四個核心概念:
1. 入口(entry)
告訴webpack從哪里開始打包,從入口開始webpack會找出所有依賴的文件??梢杂卸鄠€入口。
entry: {
main: './path/to/my/entry/file.js'
}
2. 輸出(output)
告訴webpack在哪里輸出它所創(chuàng)建的bundle,以及如何命名這些文件。我們通過 output.filename 和 output.path 屬性,來告訴 webpack bundle 的名稱,以及我們想要 bundle 生成(emit)到哪里
output: {
filename: 'my-first-webpack.bundle.js'
},
3. loader
將所有類型的文件轉(zhuǎn)換為 webpack 能夠處理的有效模塊。
在 webpack 的配置中 loader 有兩個目標(biāo):
- test 屬性,用于標(biāo)識出應(yīng)該被對應(yīng)的 loader 進(jìn)行轉(zhuǎn)換的某個或某些文件。
- use 屬性,表示進(jìn)行轉(zhuǎn)換時,應(yīng)該使用哪個 loader。
module: {
rules: [
{ test: /\.txt$/, use: 'raw-loader' }
]
}
4. 插件(plugins)
loader 被用于轉(zhuǎn)換某些類型的模塊,而插件則可以用于執(zhí)行范圍更廣的任務(wù)。插件的范圍包括,從打包優(yōu)化和壓縮,一直到重新定義環(huán)境中的變量。插件接口功能極其強(qiáng)大,可以用來處理各種各樣的任務(wù)。
想要使用一個插件,你只需要 require() 它,然后把它添加到 plugins 數(shù)組中。多數(shù)插件可以通過選項(option)自定義。你也可以在一個配置文件中因為不同目的而多次使用同一個插件,這時需要通過使用 new 操作符來創(chuàng)建它的一個實例。
plugins: [
new HtmlWebpackPlugin({template: './src/index.html'})
]
11、高階組件HOC
高階組件(HOC)是 React 中用于復(fù)用組件邏輯的一種高級技巧。HOC 自身不是 React API 的一部分,它是一種基于 React 的組合特性而形成的設(shè)計模式。
具體而言,高階組件是參數(shù)為組件,返回值為新組件的函數(shù)。
12、容器組件和展示組件
展示組件其實就相當(dāng)于可控狀態(tài)組件,由外部控制其界面展示,沒有內(nèi)部state。
容器組件為展示組件或其他組件提供數(shù)據(jù)和方法,通常由高階組件生成,比如Redux里的connect(),Relay里的createContainer()。