React函式式元件值之useRef()和useReducer()
阿新 • • 發佈:2020-12-23
一、useRef
useRef共有兩種用法,獲取子元件的例項(只有類元件可用),在函式元件中的一個全域性變數,不會因為重複 render 重複申明, 類似於類元件的 this.xxx。
1,獲取子元件例項
useRef 在使用的時候,可以傳入預設值來指定預設值,需要使用的時候,訪問 ref.current 即可訪問到元件例項:
1 // 使用 ref 子元件必須是類元件
2 class Children extends PureComponent {
3 render () {
4 const { count } = this.props
5 return (
6 <div>{ count }</div>
7 )
8 }
9 }
10 function App () {
11 const [ count, setCount ] = useState(0)
12 const childrenRef = useRef(null)
13 const onClick = useMemo(() => {
14 return () => {
15 console.log(childrenRef.current)
16 setCount((count) => count + 1)
17 }
18 }, [])
19 return (
20 <div>
21 點選次數: { count }
22 <Children ref={childrenRef} count={count}></Children>
23 <button onClick={onClick}>點我</button>
24 </div>
25 )
26 }
2,類元件屬性
有些情況下,我們需要保證函式元件每次 render 之後,某些變數不會被重複申明,比如說 Dom 節點,定時器的 id 等等,在類元件中,我們完全可以通過給類新增一個自定義屬性來保留,比如說 this.xxx, 但是函式元件沒有 this,自然無法通過這種方法使用,有的朋友說,我可以使用useState 來保留變數的值,但是 useState 會觸發元件 render,在這裡完全是不需要的,我們就需要使用 useRef 來實現了,具體看下面例子:
1 function App () {
2 const [ count, setCount ] = useState(0)
3 const timer = useRef(null)
4 let timer2
5 useEffect(() => {
6 let id = setInterval(() => {
7 setCount(count => count + 1)
8 }, 500)
9 timer.current = id
10 timer2 = id
11 return () => {
12 clearInterval(timer.current)
13 }
14 }, [])
15 const onClickRef = useCallback(() => {
16 clearInterval(timer.current)
17 }, [])
18 const onClick = useCallback(() => {
19 clearInterval(timer2)
20 }, [])
21 return (
22 <div>
23 點選次數: { count }
24 <button onClick={onClick}>普通</button>
25 <button onClick={onClickRef}>useRef</button>
26 </div>
27 )
28 }
二、useReducer
useReducer 類似 redux 中的功能,相較於 useState,它更適合一些邏輯較複雜且包含多個子值,或者下一個 state 依賴於之前的 state 等等的特定場景, useReducer 總共有三個引數
- 第一個引數是 一個 reducer,就是一個函式類似 (state, action) => newState 的函式,傳入 上一個 state 和本次的 action
- 第二個引數是初始 state,也就是預設值,是比較簡單的方法
- 第三個引數是惰性初始化,這麼做可以將用於計算 state 的邏輯提取到 reducer 外部,這也為將來對重置 state 的 action 做處理提供了便利
1 function reducer(state, action) {
2 switch (action.type) {
3 case 'increment':
4 return {count: state.count + 1};
5 case 'decrement':
6 return {count: state.count - 1};
7 default:
8 throw new Error();
9 }
10 }
11 function App() {
12 const [state, dispatch] = useReducer(reducer, {count: 0});
13 return (
14 <>
15 點選次數: {state.count}
16 <button onClick={() => dispatch({type: 'increment'})}>+</button>
17 <button onClick={() => dispatch({type: 'decrement'})}>-</button>
18 </>
19 );
20 }