從三個緯度學習記錄:react
useState
的出現是 : 在函數組件裏面使用 class的setState
,刺激!數組
解決了的問題是:當咱們一個函數組件想要有本身維護的state的時候,不得已只能轉換成class。這樣很麻煩!緩存
const [name, setName] = useState('rose') 複製代碼
😄1. 重點: useState的初始值,只在第一次有效
bash
我當時反正沒有當回事,直到遇到了坑...markdown
🌰2. 舉個例子:dom
當我點擊按鈕修改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 的出現是 : 在函數組件裏面使用 class的生命週期函數,仍是全部函數的合體!刺激!函數
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的生成執行規則有關係:看文檔去!
前面提到的:
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
的一個做用:
就是至關於全局做用域,一處被修改,其餘地方全更新...
const countRef = useRef(0)
複製代碼
😄 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) }, 1000) return ()=> clearInterval(timer) },[]) 複製代碼
😄 2. 廣泛操做,用來操做dom
const btnRef = useRef(null)
click me
活學活用,記得取消綁定事件哦! 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> ) } 複製代碼
舉個🌰:
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
做爲一個有着暫存能力的,就來了。
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
一看 就感受跟到memo有種蜜汁關係,由於都有memo...
😄 1. 首先,memo
的用法是:函數組件裏面的PureComponent
可是,若是函數組件被 React.memo 包裹,且其實現中擁有 useState 或 useContext 的 Hook,當 context 發生變化時,它仍會從新渲染。
😄 2. 並且,memo
是淺比較,意思是,對象只比較內存地址,只要你內存地址沒變,管你對象裏面的值變幻無窮都不會觸發render
😄 3. 最後,useMemo
的做用是, 因而useMemo
做爲一個有着暫存能力的,就來了:
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> ) } 複製代碼
const onChange = useCallback((e)=>{ setText(e.target.value) },[]) 複製代碼
😄1.useMemo
與 useCallback
相似,都是有着緩存的做用。本質的區別可能就是:
useMemo 是緩存值的
useCallback 是緩存函數的
😄2.沒有依賴,添加空的依賴,就是空數組!
顧名思義,useReducer
就是 class 裏面那個reducer
舉個🌰:
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 複製代碼
暫無特別的...😼
useContext
就是 class 裏面的 那個 context。
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 複製代碼
暫無特別的...😼
自定義一個當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()
複製代碼