1. 程式人生 > 實用技巧 >React函式式元件值之useRef()和useReducer()

React函式式元件值之useRef()和useReducer()

一、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 }