Function Component
可使用狀態Class Component
的生命週期this
指向問題傷破腦經render props
& HOC
嵌套缺陷如今開始咱們用建立一個計數器的方式開始學習使用
React Hooks
javascript
useState
的用法很簡單,傳入一個初始 state
,返回一個 state
以及修改 state
的函數。html
// useState 返回的 state 是個常量
// 每次組件從新渲染以後,當前 state 和以前的 state 都不相同
// 即便這個 state 是個對象
const [count, setCount] = useState(1)
複製代碼
setCount
就至關於 setState
,能夠傳入一個新的狀態或者函數。例如:java
setCount(2)
setCount(prevCount => prevCount + 1)
複製代碼
其實 useState
內部能夠簡單理解爲(只是理解):react
// 閉包存儲 state 數據
function useState(initialState){
let state = initialState;
function setState = (newState, action) => {
state = newState;
}
return [state, setState]
}
複製代碼
那接下來編寫 Count
組件:redux
function Counter() {
const [count, setCount] = React.useState(0)
return (
<div> Count: {count} <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button> <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button> </div>
);
}
複製代碼
如今咱們有了新的需求: 在 count
每次更新的時候打印 count
的值,這時咱們須要用 useEffect
來實現閉包
function Counter() {
const [count, setCount] = React.useState(0)
React.useEffect(() => {
console.log(count)
})
return (
<div> Count: {count} <button onClick={() => setCount(count + 1)}>+</button> <button onClick={() => setCount(count - 1)}>-</button> </div>
);
}
複製代碼
以上在每次從新渲染時, useEffect
就能夠實現打印,能夠把它看成是 componentDidUpdate
和 componentDidMount
, 同於 Class Component
中的函數
componentDidMount() {
console.log(count)
}
componentDidUpdate() {
console.log(count)
}
複製代碼
另外它能夠返回一個函數,用於解綁一些反作用,功能相似於 componentWillUnmount
學習
React.useEffect(() => {
console.log(count)
// 注意: 當咱們每次更新計數時,都會先打印 clean 這行 log
return () => console.log('clean', count)
})
複製代碼
爲了防止咱們沒必要要的渲染,useEffect
加入第二個參數, 只有在 count
改變的時候纔會執行。優化
React.useEffect(() => {
console.log(count)
// 當咱們每次更新計數時,都會先打印 clean 這行 log
return () => console.log('clean', count)
}, [count])
複製代碼
useReducer
是 useState
的替代方案,主要是爲了解決多個 state
子值的問題。(會Redux
的一看就會明白)ui
看一下🌰:
// 初始化 state
const initialState = {count: 0};
// 類於 redux 的 reducer
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div> Count: {state.count} /* dispatch 調用 action 操做 */ <button onClick={() => dispatch({type: 'decrement'})}>-</button> <button onClick={() => dispatch({type: 'increment'})}>+</button> </div>
);
}
複製代碼
這是個用於優化的 hook
, 返回一個 memoized 值。說白了就是會利用閉包的特性存儲上次的參數,若是和此次傳入的參數一致就返回以前的結果。這叫作記憶化技術。
下面咱們來看個反🌰:
function WithoutMemo() {
const [count, setCount] = useState(1);
const [val, setValue] = useState('');
function expensive() {
console.log('compute');
let sum = 0;
for (let i = 0; i < count * 100; i++) {
sum += i;
}
return sum;
}
return <div> <h4>{count}-{val}-{expensive()}</h4> <div> <button onClick={() => setCount(count + 1)}>+c1</button> <input value={val} onChange={event => setValue(event.target.value)}/> </div> </div>; } 複製代碼
這個函數式組件面臨的問題就是 expensive
方法無論是 count
仍是 val
改變時都會因爲組件的從新渲染, 從新計算。
可是這裏的昂貴計算只依賴於count
的值,在val
修改的時候,是沒有必要再次計算的。在這種狀況下,咱們就可使用useMemo
,只在count
的值修改時,執行expensive
計算:
// count 若是不變就不會再次執行
const expensive = React.useMemo(() => {
console.log('compute');
let sum = 0;
for (let i = 0; i < count * 100; i++) {
sum += i;
}
return sum;
}, [count]);
複製代碼
useCallback
和 useMemo
很類似,不過它返回的是函數。下面繼續看個🌰:
function Parent() {
const [count, setCount] = React.useState(1);
const [val, setVal] = React.useState('');
const callback = React.useCallback(() => {
return count;
}, [count]);
return <div>
<h4>{count}</h4>
// callback 做爲 props 傳入
<Child callback={callback}/>
<div>
<button onClick={() => setCount(count + 1)}>+</button>
<input value={val} onChange={event => setVal(event.target.value)}/>
</div>
</div>;
}
function Child({ callback }) {
const [count, setCount] = React.useState(() => callback());
React.useEffect(() => {
setCount(callback());
}, [callback]);
return (
<div>
{count}
</div>
)
}
複製代碼
如今就是有一個父組件,其中包含子組件,子組件接收一個函數做爲props;一般而言,若是父組件更新了,子組件也會執行更新;可是大多數場景下,更新是沒有必要的,咱們能夠藉助useCallback來返回函數,而後把這個函數做爲props傳遞給子組件;這樣,子組件就能避免沒必要要的更新。
useCallback(fn, deps) 至關於 useMemo(() => fn, deps)。
經過自定義 Hook,能夠將組件邏輯提取到可重用的函數中。
自定義 Hook
是一個函數,其名稱以 use
開頭,函數內部能夠調用其餘的 Hook
。
function useConsoleCount(count) {
React.useEffect(() => {
console.log(count)
// 當咱們每次更新計數時,都會先打印 clean 這行 log
return () => console.log('clean', count)
}, [count])
}
function Counter() {
const [count, setCount] = React.useState(0);
useConsoleCount(count)
return (
<div> Count: {count} <button onClick={() => setCount(count + 1)}>+</button> <button onClick={() => setCount(count - 1)}>-</button> </div>
);
}
複製代碼
hook
的使用,有錯誤的地方歡迎指正hook
可直接閱讀官方文檔