从三个纬度学习记录:
- 为什么🤔️
- 怎么用🔨
- 知识点⛽️
useState
为什么要使用useState?
useState
的出现是 : 在函数组件里面使用 class的setState
,刺激!
解决了的问题是:当我们一个函数组件想要有自己维护的state的时候,不得已只能转换成class。这样很麻烦!
如何使用useState?
const [name, setName] = useState('rose')
useState踩坑知识点
😄1. 重点: useState的初始值,只在第一次有效
我当时反正没有当回事,直到遇到了坑...
🌰2. 举个例子:
当我点击按钮修改name的值的时候,我发现在Child组件, 是收到了,但是并没有通过useState
赋值给name!
结论: 实践检验知识点!😭
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’)
<span class="hljs-built_in">return</span>(
<div>
<div>
{count}
</div>
<button onClick={()=><span class="hljs-built_in">set</span>Count(count+1)}>update count </button>
<button onClick={()=><span class="hljs-built_in">set</span>Name(<span class="hljs-string">'jack'</span>)}>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)
<button>click me </button>
活学活用,记得取消绑定事件哦! return ()=> btnRef.current.removeEventListener('click',onClick, false)
const Hook =()=>{
const [count, setCount] = useState(0)
const btnRef = useRef(null)
useEffect(() => {
console.log(<span class="hljs-string">'use effect...'</span>)
const onClick = ()=>{
<span class="hljs-built_in">set</span>Count(count+1)
}
btnRef.current.addEventListener(<span class="hljs-string">'click'</span>,onClick, <span class="hljs-literal">false</span>)
<span class="hljs-built_in">return</span> ()=> btnRef.current.removeEventListener(<span class="hljs-string">'click'</span>,onClick, <span class="hljs-literal">false</span>)
},[count])
<span class="hljs-built_in">return</span>(
<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
}
<span class="hljs-built_in">return</span>(
<div>
<div>
{count}
</div>
<button onClick={()=><span class="hljs-built_in">set</span>Count(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])
<span class="hljs-built_in">return</span>(
<div>
<div>
{count}
</div>
<button onClick={()=><span class="hljs-built_in">set</span>Count(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.useMemo
与 useCallback
类似,都是有着缓存的作用。本质的区别可能就是:
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
<span class="hljs-built_in">set</span>Width(clientWidth)
<span class="hljs-built_in">set</span>Height(clientHeight)
}, [])
useEffect(() => {
const handleWindowSize = () =>{
const {clientWidth, clientHeight} = document.documentElement
<span class="hljs-built_in">set</span>Width(clientWidth)
<span class="hljs-built_in">set</span>Height(clientHeight)
};
window.addEventListener(<span class="hljs-string">'resize'</span>, handleWindowSize, <span class="hljs-literal">false</span>)
<span class="hljs-built_in">return</span> () => {
window.removeEventListener(<span class="hljs-string">'resize'</span>,handleWindowSize, <span class="hljs-literal">false</span>)
}
})
<span class="hljs-built_in">return</span> [width, height]
}
如何使用:
const [width, height] = useWindowSize()
最后
内容来源于网络
原文出处及转载信息见文内详细说明,如有侵权,请联系 vueclub@126.com 删除