从三个纬度学习记录: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()
复制代码