終於搞懂 React Hooks了


終於搞懂 React Hooks了


學習總結!

從三個維度學習記錄:

  1. 為什麼️
  2. 怎麼用
  3. 知識點⛽️

useState

為什麼要使用useState?

useState 的出現是 : 在函數組件裡面使用 class的setState,刺激!

解決了的問題是:當我們一個函數組件想要有自己維護的state的時候,不得已只能轉換成class。這樣很麻煩!

如何使用useState?

<code>const [name, setName] = useState('rose')
複製代碼/<code>

useState踩坑知識點

1. 重點: useState的初始值,只在第一次有效

我當時反正沒有當回事,直到遇到了坑...

2. 舉個例子:

當我點擊按鈕修改name的值的時候,我發現在Child組件, 是收到了,但是並沒有通過useState賦值給name!

結論: 實踐檢驗知識點!

<code>const Child = memo(({data}) =>{
console.log('child render...', data)
const [name, setName] = useState(data)
return (

child

{name} --- {data}


);
})

const Hook =()=>{
console.log('Hook render...')
const [count, setCount] = useState(0)
const [name, setName] = useState('rose')

return(


{count}

<button>setCount(count+1)}>update count /<button>
<button>setName('jack')}>update name /<button>
<child>
/<child>

)
}
複製代碼/<code>

useEffect

為什麼要使用useEffect?

useEffect 的出現是 : 在函數組件裡面使用 class的生命週期函數,還是所有函數的合體!刺激!

如何使用useEffect?

<code>useEffect(()=>{
...
})
複製代碼/<code>

useEffect知識點合集

1.只在第一次使用的componentDidMount,可以用來請求異步數據...、

useEffect最後,加了[]就表示只第一次執行

<code>useEffect(()=>{
const users = 獲取全國人民的信息()
},[])
複製代碼/<code>

2.用來替代willUpdate等每次渲染都會執行的生命函數

useEffect最後,不加[]就表示每一次渲染都執行

<code>useEffect(()=>{
const users = 每次都獲取全國人民的信息()
})
複製代碼/<code>

3.每次渲染都執行感覺有點費,所以:

useEffect最後,加[],並且[]裡面加的字段就表示,這個字段更改了,我這個effect才執行

<code>useEffect(() => {
const users = (name改變了我才獲取全國人民的信息())
},[name])
複製代碼/<code>

4.如果我想要分別name和age呢:

可以寫多個useEffect

<code>useEffect(() => {
const users = (name改變了我才獲取全國人民的name信息())
},[name])

useEffect(() => {
const users = (name改變了我才獲取全國人民的age信息())
},[age])
複製代碼/<code>

5.如果我們之前訂閱了什麼,最後在willUnMount這個生命週期裡面要取消訂閱,這可咋用useEffect實現啊:

在effect的return裡面可以做取消訂閱的事

<code>useEffect(() => {
const subscription = 訂閱全國人民吃飯的情報!
return () => {
取消訂閱全國人民吃飯的情報!
}
},[])
複製代碼/<code>

為什麼要取消訂閱?

大家都知道,render了之後會執行重新useEffect,如果useEffect裡面有一個每setInterval...那麼每次render了,再次執行useEffect就會再創建一個setInterval,然後就混亂了...可以把下面案例return的內容刪掉感受下

<code>useEffect(() => {
console.log('use effect...',count)
const timer = setInterval(() => setCount(count +1), 1000)
return ()=> clearInterval(timer)
})
複製代碼/<code>

6.useEffect的一些暗戳戳的規則:

1.useEffect 裡面使用到的state的值, 固定在了useEffect內部, 不會被改變,除非useEffect刷新,重新固定state的值

<code> const [count, setCount] = useState(0)
useEffect(() => {
console.log('use effect...',count)
const timer = setInterval(() => {
console.log('timer...count:', count)
setCount(count + 1)
}, 1000)
return ()=> clearInterval(timer)
},[])

複製代碼/<code>

2.useEffect不能被判斷包裹

<code>const [count, setCount] = useState(0)
if(2 < 5){
useEffect(() => {
console.log('use effect...',count)
const timer = setInterval(() => setCount(count +1), 1000)
return ()=> clearInterval(timer)
})
}
複製代碼/<code>

3.useEffect不能被打斷

<code>const [count, setCount] = useState(0)
useEffect(...)

return // 函數提前結束了

useEffect(...)
}
複製代碼/<code>

具體原因跟到useEffect的生成執行規則有關係:看文檔去!

useRef

為什麼要使用useRef?

前面提到的:

useEffect 裡面使用到的state的值, 固定在了useEffect內部, 不會被改變,除非useEffect刷新,重新固定state的值

<code> const [count, setCount] = useState(0)
useEffect(() => {
console.log('use effect...',count)
const timer = setInterval(() => {
console.log('timer...count:', count)
setCount(count + 1)
}, 1000)
return ()=> clearInterval(timer)
},[])

複製代碼/<code>

useEffect裡面的state的值,是固定的,這個是有辦法解決的,就是用useRef,可以理解成useRef的一個作用:

就是相當於全局作用域,一處被修改,其他地方全更新...

如何使用useRef?

<code>const countRef = useRef(0)

複製代碼/<code>

useRef知識點合集

1. 就是相當於全局作用域,一處被修改,其他地方全更新...

<code> const [count, setCount] = useState(0)
const countRef = useRef(0)
useEffect(() => {
console.log('use effect...',count)
const timer = setInterval(() => {
console.log('timer...count:', countRef.current)
setCount(countRef.current + 1)
}, 1000)
return ()=> clearInterval(timer)
},[])
複製代碼/<code>

2. 普遍操作,用來操作dom

const btnRef = useRef(null)

click me

活學活用,記得取消綁定事件哦! return ()=> btnRef.current.removeEventListener('click',onClick, false)

<code>const Hook =()=>{
const [count, setCount] = useState(0)
const btnRef = useRef(null)

useEffect(() => {
console.log('use effect...')
const onClick = ()=>{
setCount(count+1)
}
btnRef.current.addEventListener('click',onClick, false)
return ()=> btnRef.current.removeEventListener('click',onClick, false)
},[count])

return(


{count}

<button>click me /<button>

)
}
複製代碼/<code>

useMemo

為什麼要使用useMemo?

舉個:

<code>const Child = memo(({data}) =>{
console.log('child render...', data.name)
return (

child

{data.name}


);
})

const Hook =()=>{
console.log('Hook render...')
const [count, setCount] = useState(0)
const [name, setName] = useState('rose')

const data = {
name
}

return(


{count}

<button>setCount(count+1)}>update count /<button>
<child>
/<child>

)
}
複製代碼/<code>

當我們點擊按鈕更新count的時候,Effect組件會render,一旦render, 執行到這一行代碼:

<code>   const data = {
name
}
複製代碼/<code>

這一行代碼會生成有新的內存地址的對象,那麼就算帶著memo的Child組件,也會跟著重新render, 儘管最後其實Child使用到的值沒有改變!

這樣就多餘render了,感覺性能浪費了!於是useMemo 作為一個有著暫存能力的,就來了。

如何使用useMemo?

<code>  const data = useMemo(()=>{
return {
name
}
},[name])
複製代碼/<code>

的時候,就會先根據[name]裡面的name值判斷一下,因為useMemo 作為一個有著暫存能力的,暫存了上一次的name結果。

結果一對比上一次的name,我們發現name值居然沒有改變!那麼這次data就不重新賦值成新的對象了!

沒有新的對象,就沒有新的內存地址,那麼Child就不會重新render!

<code>const Child = memo(({data}) =>{
console.log('child render...', data.name)
return (

child

{data.name}


);
})

const Hook =()=>{
console.log('Hook render...')
const [count, setCount] = useState(0)
const [name, setName] = useState('rose')

const data = useMemo(()=>{
return {
name
}
},[name])

return(


{count}

<button>setCount(count+1)}>update count /<button>
<child>
/<child>

)
}
複製代碼/<code>

useMemo知識點合集

useMemo 一看 就感覺跟到memo有種蜜汁關係,因為都有memo...

1. 首先,memo 的用法是:函數組件裡面的PureComponent

但是,如果函數組件被 React.memo 包裹,且其實現中擁有 useState 或 useContext 的 Hook,當 context 發生變化時,它仍會重新渲染。

2. 而且,memo是淺比較,意思是,對象只比較內存地址,只要你內存地址沒變,管你對象裡面的值千變萬化都不會觸發render

3. 最後,useMemo 的作用是, 於是useMemo 作為一個有著暫存能力的,就來了:

useCallback

為什麼要使用useCallback?

useMemo 解決了值的緩存的問題,那麼函數呢?

下面這個就是,當點擊count的按鈕,Effect組件render,遇到了:

<code>   const onChange=(e)=>{
setText(e.target.value())
}

複製代碼/<code>

則,重新生成了一個onChange函數,賦值給了Child組件,淺比較失敗,Child組件成功重新render,儘管Child組件什麼都沒有做!

<code>const Child = memo(({data, onChange}) =>{
console.log('child render...')
return (

child

{data}



);
})

const Hook =()=>{
console.log('Hook render...')
const [count, setCount] = useState(0)
const [name, setName] = useState('rose')
const [text, setText] = useState('')

const onChange=(e)=>{
setText(e.target.value())
}

return(

count: {count}

text : {text}

<button>setCount(count + 1)}>count + 1/<button>
<child>
/<child>

)
}

複製代碼/<code>

如何使用useCallback?

<code>   const onChange = useCallback((e)=>{
setText(e.target.value())
},[])
複製代碼/<code>

useCallback 知識點合集

1.useMemo 與 useCallback 類似,都是有著緩存的作用。本質的區別可能就是:

useMemo 是緩存值的

useCallback 是緩存函數的

2.沒有依賴,添加空的依賴,就是空數組!

useReducer

為什麼要使用useReducer?

顧名思義,useReducer就是 class 裡面那個reducer

如何使用useReducer?

舉個:

<code>const reducer =(state = 0, {type})=>{
switch (type) {
case "add":
return state+1
case 'delete':
return state-1
default:
return state;
}
}

const Hook =()=>{
const [count, dispatch] = useReducer(reducer, 0)

return(

count:{count}
<button> dispatch({type:'add'})}>add/<button>
<button> dispatch({type:'delete'})}>delete/<button>

)
}

export default Hook
複製代碼/<code>

useReducer知識點合集

暫無特別的...

useContext

為什麼要使用useContext?

useContext 就是 class 裡面的 那個 context。

如何使用useContext?

<code>import React, {useContext, useReducer} from 'react'

const reducer = (state = 0, {type}) => {
switch (type) {
case "add":
return state + 1
case 'delete':
return state - 1
default:
return state;
}
}
const Context = React.createContext(null);

const Child = () => {
const [count, dispatch] = useContext(Context)
return (

child...{count}

<button> dispatch({type: 'add'})}>child add/<button>
<button> dispatch({type: 'delete'})}>child delete/<button>


)
}

const Hook = () => {
const [count, dispatch] = useReducer(reducer, 10)
return (
<context.provider>

mom ... {count}

<child>
<button> dispatch({type: 'add'})}>mom add/<button>
<button> dispatch({type: 'delete'})}>mom delete/<button>

/<context.provider>
)
}

export default Hook

複製代碼/<code>

useContext知識點合集

暫無特別的...

自定義hook!

自定義一個當resize 的時候 監聽window的width和height的hook

<code>import {useEffect, useState} from "react";

export const useWindowSize = () => {
const [width, setWidth] = useState()
const [height, setHeight] = useState()

useEffect(() => {
const {clientWidth, clientHeight} = document.documentElement

setWidth(clientWidth)
setHeight(clientHeight)
}, [])

useEffect(() => {
const handleWindowSize = () =>{
const {clientWidth, clientHeight} = document.documentElement
setWidth(clientWidth)
setHeight(clientHeight)
};

window.addEventListener('resize', handleWindowSize, false)

return () => {
window.removeEventListener('resize',handleWindowSize, false)
}
})

return [width, height]
}

複製代碼/<code>

如何使用:

<code>const [width, height] = useWindowSize()
複製代碼/<code>

最後


終於搞懂 React Hooks了


分享到:


相關文章: