終於搞懂 React Hooks了!!!!!

學習總結!

從三個緯度學習記錄:react

  1. 爲何🤔️
  2. 怎麼用🔨
  3. 知識點⛽️

useState

爲何要使用useState?

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

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

如何使用useState?

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

useState踩坑知識點

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

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

🌰2. 舉個例子:異步

當我點擊按鈕修改name的值的時候,我發如今Child組件, 是收到了,可是並無經過useState賦值給name!ide

結論: 實踐檢驗知識點!😭函數

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

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

    return(
        <div>
            <div>
                {count}
            </div>
            <button onClick={()=>setCount(count+1)}>update count </button>
            <button onClick={()=>setName('jack')}>update name </button>
            <Child data={name}/>
        </div>
    )
}
複製代碼

useEffect

爲何要使用useEffect?

useEffect 的出現是 : 在函數組件裏面使用 class的生命週期函數,仍是因此函數的合體!刺激!性能

如何使用useEffect?

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

useEffect知識點合集

😄1.只在第一次使用的componentDidMount,能夠用來請求異步數據...、學習

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

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

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

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

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

😄3.每次渲染都執行感受有點費,因此:

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

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

😄4.若是我想要分別name和age呢:

能夠寫多個useEffect

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

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

😄5.若是咱們以前訂閱了什麼,最後在willUnmount這個生命週期裏面要取消訂閱,這可咋用useEffect實現啊:

在effect的return裏面能夠作取消訂閱的事

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

爲何要取消訂閱?

你們都知道,render了以後會執行從新useEffect,若是useEffect裏面有一個每setInterval...那麼每次render了,再次執行useEffect就會再建立一個setInterval,而後就混亂了...能夠把下面案例return的內容刪掉感覺下

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

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

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

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)
    },[])
    
複製代碼

2.useEffect不能被判斷包裹

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

3.useEffect不能被打斷

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

return // 函數提早結束了

useEffect(...)
}
複製代碼

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

useRef

爲何要使用useRef?

前面提到的:

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

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)
    },[])
    
複製代碼

useEffect裏面的state的值,是固定的,這個是有辦法解決的,就是用useRef,能夠理解成useRef的一個做用:

就是至關於全局做用域,一處被修改,其餘地方全更新...

如何使用useRef?

const countRef = useRef(0)

複製代碼

useRef知識點合集

😄 1. 就是至關於全局做用域,一處被修改,其餘地方全更新...

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)
},[])
複製代碼

😄 2. 廣泛操做,用來操做dom

const btnRef = useRef(null)

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

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(
        <div>
            <div>
                {count}
            </div>
            <button ref={btnRef}>click me </button>
        </div>
    )
}
複製代碼

useMemo

爲何要使用useMemo?

舉個🌰:

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

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

    const data = {
        name
    }

    return(
        <div>
            <div>
                {count}
            </div>
            <button onClick={()=>setCount(count+1)}>update count </button>
            <Child data={data}/>
        </div>
    )
}
複製代碼

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

const data = {
        name
    }
複製代碼

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

這樣就多餘render了,感受性能浪費了!因而useMemo 做爲一個有着暫存能力的,就來了。

如何使用useMemo?

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

的時候,就會先根據[name]裏面的name值判斷一下,由於useMemo 做爲一個有着暫存能力的,暫存了上一次的name結果。

結果一對比上一次的name,咱們發現name值竟然沒有改變!那麼此次data就不從新賦值成新的對象了!

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

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

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

   const data = useMemo(()=>{
        return {
            name
        }
    },[name])
    
    return(
        <div>
            <div>
                {count}
            </div>
            <button onClick={()=>setCount(count+1)}>update count </button>
            <Child data={data}/>
        </div>
    )
}
複製代碼

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,遇到了:

const onChange=(e)=>{
        setText(e.target.value())
   }
    
複製代碼

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

const Child = memo(({data, onChange}) =>{
    console.log('child render...')
    return (
        <div>
            <div>child</div>
            <div>{data}</div>
            <input type="text" onChange={onChange}/>
        </div>
    );
})

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(
        <div>
            <div>count: {count}</div>
            <div>text : {text}</div>
            <button onClick={()=>setCount(count + 1)}>count + 1</button>
            <Child data={name} onChange={onChange}/>
        </div>
    )
}

複製代碼

如何使用useCallback?

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

useCallback 知識點合集

😄1.useMemouseCallback 相似,都是有着緩存的做用。本質的區別可能就是:

useMemo 是緩存值的

useCallback 是緩存函數的

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

useReducer

爲何要使用useReducer?

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

如何使用useReducer?

舉個🌰:

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(
        <div>
           count:{count}
           <button onClick={()=> dispatch({type:'add'})}>add</button>
            <button onClick={()=> dispatch({type:'delete'})}>delete</button>
        </div>
    )
}

export default Hook
複製代碼

useReducer知識點合集

暫無特別的...😼

useContext

爲何要使用useContext?

useContext 就是 class 裏面的 那個 context。

如何使用useContext?

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 (
        <div>
            <div>child...{count}</div>
            <button onClick={() => dispatch({type: 'add'})}>child add</button>
            <button onClick={() => dispatch({type: 'delete'})}>child delete</button>
        </div>

    )
}

const Hook = () => {
    const [count, dispatch] = useReducer(reducer, 10)
    return (
        <Context.Provider value={[count, dispatch]}>
            <div>
                <div>mom ... {count}</div>
                <Child/>
                <button onClick={() => dispatch({type: 'add'})}>mom add</button>
                <button onClick={() => dispatch({type: 'delete'})}>mom delete</button>
            </div>
        </Context.Provider>
    )
}

export default Hook

複製代碼

useContext知識點合集

暫無特別的...😼

自定義hook!

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

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]
}

複製代碼

如何使用:

const [width, height] = useWindowSize()
複製代碼

最後

相關文章
相關標籤/搜索