React Hooks系列之useRef

前言

react hooks 是 React 16.8 的新增特性。 它可以讓我們在函數組件中使用 state 、生命週期以及其他 react特性,而不僅限於 class 組件。react hooks 的出現,標示着 react中不會在存在無狀態組件了,只有類組件和函數組件。具體可查看官網

優勢:

  1. 函數組件不能使用state,遇到交互更改狀態等複雜邏輯時不能更好地支持,hooks讓函數組件更靠近class組件,擁抱函數式編程。
  2. 解決副作⽤問題,hooks出現可以處理數據獲取、訂閱、定時執行任務、手動修改 ReactDOM這些⾏爲副作用,進行副作用邏輯。比如useEffect。
  3. 更好寫出有狀態的邏輯重用組件。
  4. 讓複雜邏輯簡單化,比如狀態管理:useReducer、useContext。
  5. 函數式組件比class組件簡潔,開發的體驗更好,效率更⾼,性能更好。
  6. 更容易發現無用的狀態和函數。

useRef介紹

const refContainer = useRef(initialValue);

useRef 返回一個可變的 ref 對象,其 .current 屬性被初始化爲傳入的參數(initialValue)。返回的 ref 對象在組件的整個生命週期內保持不變。

本質上,useRef 就像是可以在其 .current 屬性中保存一個可變值的“盒子”。

然而,useRef() 比 ref 屬性更有用。它可以很方便地保存任何可變值,其類似於在 class 中使用實例字段的方式。

這是因爲它創建的是一個普通 Javascript 對象。而 useRef() 和自建一個 {current: …} 對象的唯一區別是,useRef 會在每次渲染時返回同一個 ref 對象。

請記住,當 ref 對象內容發生變化時,useRef 並不會通知你。變更 .current 屬性不會引發組件重新渲染。如果想要在 React 綁定或解綁 DOM 節點的 ref 時運行某些代碼,則需要使用回調 ref 來實現。

useRef 有什麼作用呢,其實很簡單,總共有三種用法

  • 作用於Dom元素
  • 獲取子組件的實例(只有類組件可用)
  • 在函數組件中的一個全局變量,不會因爲重複 render 重複申明, 類似於類組件的 this.xxx

useRef使用

作用於Dom元素

 
const UseRefComp=()=>{ 
		//創建ref
		const inputRef=useRef() 
		const getValue= () => {
		//訪問ref
			console.log(inputRef.current.value) }
		//掛載 
		return (
		<div>
		<input ref={inputRef} type="text"> <button onClick={getValue}>獲取input的
		值</button> </div>
) }

獲取子組件的實例(只有類組件可用)

// 使用 ref 子組件必須是類組件
class Children extends PureComponent {
  render () {
    const { count } = this.props
    return (
      <div>{ count }</div>
    )
  }
}

function App () {
  const [ count, setCount ] = useState(0)
  const childrenRef = useRef(null)
  // const 
  const onClick = useMemo(() => {
    return () => {
      console.log('button click')
      console.log(childrenRef.current)
      setCount((count) => count + 1)
    }
  }, [])
  return (
    <div>
      點擊次數: { count }
      <Children ref={childrenRef}  count={count}></Children>
      <button onClick={onClick}>點我</button>
    </div>
    )
}

在函數組件中的一個全局變量,不會因爲重複 render 重複申明, 類似於類組件的 this.xxx

簡單例子:

function Test(){

const t=useRef(null);

const handleClick = ()=>{
	t.current=setTimeout(()=>{
		console.log('timer')
	},1000)
}
const handleClear = () => clearTimeout(t.current)

return (
	<>
		<button onClick={handleClick}>start</button>
		<button onClick={handleClear}>clear</button>
	</>
)}

有些情況下,我們需要保證函數組件每次 render 之後,某些變量不會被重複申明,比如說 Dom 節點,定時器的 id 等等,在類組件中,我們完全可以通過給類添加一個自定義屬性來保留,比如說 this.xxx, 但是函數組件沒有 this,自然無法通過這種方法使用,有的朋友說,我可以用useState 來保留變量的值,但是 useState 會觸發組件 render,在這裏完全是不需要的,我們就需要使用 useRef 來實現了,具體看下面例子

function App () {
  const [ count, setCount ] = useState(0)
  const timer = useRef(null)
  let timer2 
  
  useEffect(() => {
    let id = setInterval(() => {
      setCount(count => count + 1)
    }, 500)

    timer.current = id
    timer2 = id
    return () => {
      clearInterval(timer.current)
    }
  }, [])

  const onClickRef = useCallback(() => {
    clearInterval(timer.current)
  }, [])

  const onClick = useCallback(() => {
    clearInterval(timer2)
  }, [])

  return (
    <div>
      點擊次數: { count }
      <button onClick={onClick}>普通</button>
      <button onClick={onClickRef}>useRef</button>
    </div>
    )
}

當我們們使用普通的按鈕去暫停定時器時發現定時器無法清除,因爲 App 組件每次 render,都會重新申明一次 timer2, 定時器的 id 在第二次 render 時,就丟失了,所以無法清除定時器,針對這種情況,就需要使用到 useRef,來爲我們保留定時器 id,類似於 this.xxx,這就是 useRef 的另外一種用法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章