Hook FAQ
hook并不能覆盖所有class所有使用场景
1 .getSnapshotBeforeUpdate,getDervedStateFromError,componentDidCatch这几个生命周期还没有对应的学法
2 .如果组件必须要需要这几个生命周期函数,可以使用class形式
从Class迁徙到Hook
1 .constructor:函数组件不需要构造函数,你可以通过调用useState来初始化state.
2 .getDerivedStateFromProps
1 .改成在渲染时安排一次更新
3 .shouldComponentUpdate:
1 .memo
4 .render:这是函数本身组件
5 .componentDidMount,componentDidUpdate,compoenntWillUnmount:
1 .useEffect hook
6 .getSnapshotBeforeUpdate,componentDidiCatch,getDerivedStateFromError
1 .目前没有对应的hook写法,需要下一个版本
进行数据获取
实例变量
1 .useRef 类似一个class的实例属性。ref对象的current属性可以变化,而且可以容纳任意值的通用容器
function Timer() {
const intervalRef = useRef();
useEffect(() => {
const id = setInterval(() => {
// ...
});
intervalRef.current = id;
return () => {
clearInterval(intervalRef.current);
};
});
function handleCancelClick() {
clearInterval(intervalRef.current);
}
//可以在别的函数里面手动关闭
}
单个还是多个state变量
1 .把state切分成多个state变量,每个变量包含的不同值
获取上一轮的props或者state
看到的是旧的state值
1 .在先点击handleAlertClick 这个函数,这个等待执行的时候,再次改变state的值,此时如果有依赖的话,是不会显示最新的值,而是直接使用原来的
2 .组件内部的任何函数,包括时间处理函数和effect,都是被从他们创建的那次渲染中被绑定数据的
3 .如果想要从异步回调中读取最新的值,可以创建一个ref来保存值,并读取他
import React,{useState} from 'react'
function Example(){
const [count,setCount]=useState(0)
function handleAlertClick(){
setTimeout(()=>{
console.log('count',count)
},3000)
}
// 第一次渲染这个函数的时候其实已经计算好了,这里会显示0
return (
<div>
<p>you click {count}times</p>
<button onClick={()=>setCount(count+1)}> click me</button>
<button onClick={handleAlertClick}>Show comsole</button>
</div>
)
}export default Example
//变成ref就能获取到最新的值,即使在获取的阶段进行更新
import React,{useState,useRef} from 'react'
function Example(){
const [count,setCount]=useState(0)
const ref=useRef(0)
ref.current=0
function handleAlertClick(){
setTimeout(()=>{
console.log('count',ref.current)
},3000)
}
// 第一次渲染这个函数的时候其实已经计算好了,这里会显示0
return (
<div>
<p>you click {count}times</p>
<button onClick={()=>ref.current=10}> click me</button>
<button onClick={handleAlertClick}>Show comsole</button>
</div>
)
}export default Example
Class 组件和function组件的渲染效率
1 .函数组件每次渲染创建大量的闭包,传统的class组件的render非常简洁
2 .在现代浏览器中,只有特别极端的场景下才会有明显的差别
3 .hook避免了class需要的额外开销,比如创建类实例以及构造函数中绑定事件处理器的成本
4 .符合语言习惯的代码在使用hook时不需要很深的组件嵌套。
5 .同样的功能,类组件和函数组件的效率是不相上下的,但是函数组件是未来趋势
6 .
引用类型的数据不能感知到变化
function useTest(){
const [Arr,setArr]=useState([])
const [count,setCount]=useState(0)
useEffect(()=>{
function handleClick(){
console.log('click')
const data=new Date()
const arr=Arr
arr.push(data)
setArr(arr)
setCount(count+1)
console.log(arr)
}
document.addEventListener("click",handleClick)
},[])
// 如果这里不加[],别的hook执行,触发render,那么这个也会每次都执行,那么这里就也会每次render都执行,一直往数组里面push东西,所以下一次点击的时候数组里面会保存很多
useEffect(()=>{
console.log('change')
// 这个数组的检测其实是不能触发到的
// 引用类型的值其实这里是不能操作的
},[Arr])
}
只能再最顶层使用hook
1 .不能再循环,条件,或者嵌套函数里面调用。只有这样才能在hook每一次调用的时候按照相同的顺序被调用。
2 .保证react能够在多次的useState,useEffect调用之间保持hook状态的正确
3 .只能在react函数种调用hook,不能再普通js函数里面调用hook
4 .只要hook的调用顺序在多次渲染之间保持一致,react就能正确的将内部state和对应的Hook进行关联
useEffect模拟comonentDidMount生命周期
1 .可以使用useEffect(fn, []),但是他们并不完全相等
2 .useEffect会捕获props,state,你拿到的值仅仅是初始的,执行这个函数的时候对应的值
3 .如果想要拿到最新的值,需要使用ref
4 .试图找到effect和生命周期一致的表达更容易使你混淆,需要做的还是要跳出生命周期函数
5 .