对于近期工作中使用的React Hooks进行一个总结,以及使用了Hooks的函数式组件和传统类组件的简单比较,欢迎补充、修正和探讨
useState
下面的代码是使用了useState的再简单不过的案例,定义一个数组,里面接受两个参数,第一个表示状态属性,第二个为修改属性的方法,useState中接受的参数作为状态的初始值
import { useState } from 'react';
function Example() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
)
}
useState的使用方法与setState基本相同,但在特性上有些许的不同,例如useState不会天生的支持async/await了,而setState是可以直接使用await的。但是通过useEffect,也的确不需要使用await来等待状态改变的操作完成了
useEffect
useEffect函数可以理解为类组件中componentDidMount、componentDidUpdate、componentWillUnmount三个生命周期函数的集合,useEffect接受两个参数,第一个参数是一个是回调函数,这是需要执行的副作用函数,第二个参数是一个依赖数组,当数组中依赖的值发生改变时,这个回调函数就会执行。
function App() {
const [data, setData] = useState([]);
useEffect(() => {
const result = "后台数据"
setData(result.data);
}, []);
//依赖数组为空时,无论其他参数如何变化,只会渲染一次,通过这个特性,我们可以
//用来模仿componentDidMount钩子
useEffect(async () => {
console.log("数据更新")
}, [data]);
//当依赖数组中有值时,类似于componentDidUpdate钩子,且由于依赖数组的存在,我们会
//自然而然的把针对某个参数的操作写在一处,代码更具有可读性
return (
<ul>
{data.map(item => (
<li key={item.objectID}>
{item.text}
</li>
))}
</ul>
);
}
export default App;
我们在上面的代码块中实现的componentDidUpdate钩子其实是有缺陷的,因为在初始化时这个update同样会执行,如果需要一个纯粹的只在更新时执行的函数,会产生一些问题,我们可以通过搭配useRef的方法实现这样一个纯粹的update函数
const isUpdate = useRef(false)
useEffect(()=>{
if(isUpdate.current){
//...
} else {
isUpdate.current=true
}
},[data])
使用useEffect不支持像下面这样使用async直接操作否则会产生错误
useEffect(async () => {
const result = await axios(
'http://localhost/getData',
);
setData(result.data);
}, []);
报错原因官方已经说的十分详细,即useeffect的返回值只能是空或者一个函数,但我们在用async函数返回的是一个Promise对象,与react要求不符。官方建议我们直接封装一个支持async的函数在useEffect内部使用。
而官方提到的这个返回值中接受的函数,其实就是类组件中对应的componentWillUnmount生命周期函数,假如这个组件有可能发生内存泄漏,我们可以在这里清理。