react組件分爲如下幾種:vue
一、功能組件(無狀態組件)react
Functional (Stateless) Component,功能組件也叫無狀態組件,通常只負責渲染。redux
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
複製代碼
二、類組件(有狀態組件)
Class (Stateful) Component,類組件也是有狀態組件,也能夠叫容器組件。通常有交互邏輯和業務邏輯。數組
class Welcome extends React.Component {
state = {
name: ‘tori’,
}
componentDidMount() {
fetch(…);
…
}
render() {
return (
<> <h1>Hello, {this.state.name}</h1> <button onClick={() => this.setState({name: ‘007’})}>更名</button> </>
);
}
}
複製代碼
三、渲染組件 Presentational Component,和功能(無狀態)組件相似。瀏覽器
const Hello = (props) => {
return (
<div> <h1>Hello! {props.name}</h1> </div>
)
}
複製代碼
Hook 出現以前,組件之間複用狀態邏輯很難,解決方案(HOC、Render Props)都須要從新組織組件結構, 且代碼難以理解。在React DevTools 中觀察過 React 應用,你會發現由 providers,consumers,高階組件,render props 等其餘抽象層組成的組件會造成「嵌套地獄」。
組件維護愈來愈複雜,譬如事件監聽邏輯要在不一樣的生命週期中綁定和解綁,複雜的頁面componentDidMount包涵不少邏輯,代碼閱讀性變得不好。
class組件中的this難以理解,且class 不能很好的壓縮,而且會使熱重載出現不穩定的狀況。更多引子介紹參見官方介紹。
因此hook就爲解決這些問題而來:緩存
useState 是 React Hooks 中很基本的一個 API,它的用法主要有這幾種:性能優化
1. const [ count1, setCount1 ] = useState(0);
1. const [ count2, setCount2 ] = useState(() => 0);
1. setCount1(1); // 修改 state
複製代碼
class this.setState更新是state是合併, useState中setState是替換。markdown
useState 和 class state 的區別 雖然函數組件也有了 state,可是 function state 和 class state 仍是有一些差別:閉包
關於第2點,舉個例子less
在第一個例子中,連續點擊十次,頁面上的數字會從0增加到10。而第二個例子中,連續點擊十次,頁面上的數字只會從0增加到1
class 組件裏面能夠經過 this.state 引用到 count,因此每次 setTimeout 的時候都能經過引用拿到上一次的最新 count,因此點擊多少次最後就加了多少。
在 function component 裏面每次更新都是從新執行當前函數,也就是說 setTimeout 裏面讀取到的 count 是經過閉包獲取的,而這個 count 實際上只是初始值,並非上次執行完成後的最新值,因此最後只加了1次。
要解決上面這個問題,就須要使用useRef,useRef是一個對象,他擁有一個current屬性,而且無論函數組件執行多少次,useRef返回的對象永遠都是原來的那一個
useRef 有下面這幾個特色:
useRef
是一個只能用於函數組件的方法。useRef
是除字符串 ref
、函數 ref
、createRef
以外的第四種獲取 ref
的方法。useRef
在渲染週期內永遠不會變,所以能夠用來引用某些數據。ref.current
不會引起組件從新渲染。useEffect
是一個 Effect Hook
,經常使用於一些反作用的操做,在必定程度上能夠充當 componentDidMount
、componentDidUpdate
、componentWillUnmount
這三個生命週期。useEffect
是很是重要的一個方法,能夠說是 React Hooks 的靈魂,它用法主要有這麼幾種:
useEffect
接收兩個參數,分別是要執行的回調函數、依賴數組。componentDidMount
)執行,返回的函數會在組件卸載時(componentWillUnmount
)執行。componentDidMount
和 componentDidUpdate
)執行。useEffect 比較重要,它主要有這幾個做用:
useLayoutEffect 也是一個 Hook 方法,從名字上看和 useEffect 差很少,他倆用法也比較像。在90%的場景下咱們都會用 useEffect,然而在某些場景下卻不得不用 useLayoutEffect。useEffect 和 useLayoutEffect 的區別是:
例如咱們使用useEffect方法來更新Demo的位置,那麼在頁面渲染時,咱們就會看到Demo原來的位置,而後這個時候useEffect方法纔會執行,更新Demo的位置,咱們就會在頁面上看到Demo位置的變化,可是有的時候咱們不想讓用戶看到這個變化的過程,會比較醜,好比變動一個元素的位置,就會變成閃現過去,這個時候就須要使用useLayoutEffect
跨組件共享數據的鉤子函數
const value = useContext(MyContext);
// MyContext 爲 context 對象(React.createContext 的返回值)
// useContext 返回MyContext的返回值。
// 當前的 context 值由上層組件中距離當前組件最近的<MyContext.Provider> 的 value prop 決定。
複製代碼
useContext 的組件總會在 context 值變化時從新渲染, 因此<MyContext.Provider>包裹的越多,層級越深,性能會形成影響。 <MyContext.Provider>的value 發生變化時候,包裹的組件不管是否訂閱content value,全部組件都會從新渲染。
const [state, dispatch] = useReducer(reducer, initialState);
複製代碼
reducer就是一個只能經過action將state從一個過程轉換成另外一個過程的純函數;
useReducer就是一種經過(state,action) => newState的過程,和redux工做方式同樣。 數據流: dispatch(action) => reducer更新state => 返回更新後的state
官方推薦如下場景須要useReducer更佳:
使用reducer有助於將讀取與寫入分開。
useMemo 的用法相似 useEffect,經常用於緩存一些複雜計算的結果。useMemo 接收一個函數和依賴數組,當數組中依賴項變化的時候,這個函數就會執行,返回新的值。
const sum = useMemo(() => {
// 一系列計算
}, [count])
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);; 返回一個 memoized 值,和useCallback同樣,當依賴項發生變化,纔會從新計算 memoized 的值。useMemo和useCallback不一樣之處是:它容許你將memoized應用於任何值類型(不只僅是函數)。
複製代碼
DatePicker 組件每次打開或者切換月份的時候,都須要大量的計算來算出當前須要展現哪些日期。而後再將計算後的結果渲染到單元格里面,這裏可使用 useMemo 來緩存,只有當傳入的日期變化時纔去計算。
和 useMemo 相似,只不過 useCallback 是用來緩存函數。
const memoizedCallback = useCallback( () => { doSomething(a, b); }, [a, b], );
//返回一個 memoized 回調函數。
複製代碼
總結: useCallback將返回一個記憶的回調版本,僅在其中一個依賴項已更改時才更改。當將回調傳遞給依賴於引用相等性的優化子組件以防止沒必要要的渲染時,此方法頗有用。使用回調函數做爲參數傳遞,每次render函數都會變化,也會致使子組件rerender, useCallback能夠優化rerender。