前言
react hooks 是 React 16.8 的新增特性。 它可以讓我們在函數組件中使用 state 、生命週期以及其他 react特性,而不僅限於 class 組件。react hooks 的出現,標示着 react中不會在存在無狀態組件了,只有類組件和函數組件。具體可查看官網。
優勢:
- 函數組件不能使用state,遇到交互更改狀態等複雜邏輯時不能更好地支持,hooks讓函數組件更靠近class組件,擁抱函數式編程。
- 解決副作⽤問題,hooks出現可以處理數據獲取、訂閱、定時執行任務、手動修改 ReactDOM這些⾏爲副作用,進行副作用邏輯。比如useEffect。
- 更好寫出有狀態的邏輯重用組件。
- 讓複雜邏輯簡單化,比如狀態管理:useReducer、useContext。
- 函數式組件比class組件簡潔,開發的體驗更好,效率更⾼,性能更好。
- 更容易發現無用的狀態和函數。
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 的另外一種用法。