一、react hook介绍
Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。目的是解决React的状态逻辑复用问题,因为React Hooks只共享数据处理逻辑,并不会共享数据本身。
在React应用开发中,状态管理是组件开发必不可少的内容。以前,为了对状态进行管理,最通常的做法是使用类组件或者直接使用redux等状态管理框架。现在,开发者可以直接使用React Hooks提供的State Hook来处理状态。
众所周知,React提供了两种创建组件的方式,即函数组件和类组件。函数组件是一个普通的JavaScript函数,接受props对象并返回React元素,函数组件更符合React数据驱动视图的开发思想。不过,函数组件缺乏类组件诸如状态、生命周期等种种特性,而Hooks的出现就是让函数式组件拥有类组件的特性。
为了让函数组件拥有类组件的诸如状态、生命周期等特性,React 提供了3个核心的api,即state hook 、Effect hook以及自定义 hook。
二、react hook的使用方法
import React, { useState } form 'react';
function Example() {
// useState 方法返回一个数组。第一个值是当前的 state,第二个值是更新 state 的函数,相当于类组件的setState。
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>点我加1</button>
</div>
);
}
如上示例,这个函数组件有自己的状态,并且还可以更新自己的状态。useState用于创建一个新的状态,参数为一个固定的值(初始值,作为useState的参数来将其初始化为 0)或者一个有返回值的方法。执行后的结果为一个数组,分别为生成的状态count以及改变该状态的方法setCount,通过解构赋值的方法拿到对应的值与方法。
函数组件中如果存在多个状态,既可以通过一个useState声明对象类型的状态,也可以通过useState多次声明状态。
const [count, setCount] = useState({
count1: 0,
count2: 0
});
或者
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(0);
三、Effect hook 的使用方法
Effect Hook 可以在函数组件中执行副作用操作,主要用于以下两种情况:
1.函数式组件中不存在传统类组件生命周期的概念,如果我们需要在一些特定的生命周期或者值变化后做一些操作的话,必须借助useEffect的一些特性去实现。
2.useState产生的 changeState 方法并没有提供类似于setState的第二个参数一样的功能,因此如果需要在 State 改变后执行一些方法,必须通过useEffect实现。
该钩子接受两个参数,第一个参数为副作用需要执行的回调,生成的回调方法内可以返回一个函数(将在组件卸载时运行);第二个为该副作用监听的状态数组,当对应状态发生变动时会执行副作用,如果第二个参数为空,那么在每一个 State 变化时都会执行该副作用。
const [count, changeCount] = useState(0);
// 将在count变化时打印最新的count数据
useEffect(()=> {
message.info(`count发生变动,最新值为${count}`);
}, [count])
在上面的例子中,我们实现了利用useState实现了setState后执行某个方法,那如果想要实现componentDidMount和componentWillUnmout生命周期的功能呢?
首先所有的副作用在组件挂载完成后会执行一次 ,如果副作用存在返回函数,那么返回的函数将在卸载时运行。我们要做的就是让与该副作用相关联的状态为空数组,不管其他状态如何变动,该副作用都不会再次执行,于是就实现了componentDidMount和componentWillUnmout。
functionChild({ visible }){
useEffect(()=> {
message.info('我只在页面挂载时打印');
return ()=> {
message.info('我只在页面卸载时打印');
};
}, []);
return visible ? 'true' : 'false';
}
在上面示例中,我们实现了componentDidMount和componentWillUnmout,那么如何实现componentDidUpdate呢?其实,只要第二个参数为空(注意不是上面示例中的空数据,而是不传第二个参数),那么在每一个 State 变化时都会执行该副作用了。
useEffect(()=> {
……
})
四、如何自定义Hook
众所周知,要在类组件之间共享一些状态逻辑是非常麻烦的,常规做法是通过高阶组件或函数的属性来解决。不过,新版的React允许开发者创建自定义Hook来封装共享状态逻辑,且不需要向组件树中增加新的组件。
所谓的自定义Hook,其实就是指函数名以use开头并调用其他Hook的函数,自定义Hook的每个状态都是完全独立的。
export const useAxios = (url, dependencies) => {
const [isLoading, setIsLoading] = useState(false);
const [response, setResponse] = useState(null);
useEffect(() => {
setIsLoading(true);
axios.get(url).then((res) => {
setIsLoading(false);
setResponse(res);
}).catch((err) => {
setIsLoading(false);
});
}, dependencies);
return [isLoading, response, error];
};
使用自定义方法:
function Example() {
let url = 'http://www.baidu.com/api/xxx';
const [isLoading, response, error] = useAxios(url, []);
...
}
export default Example;
五、使用Hooks的注意事项:
1.不要在循环、条件或嵌套函数中使用Hook,并且只能在React函数的顶层使用Hook。因为React需要利用调用顺序来正确更新相应的状态,以及调用相应的生命周期函数函数。一旦在循环或条件分支语句中调用Hook,就容易导致调用顺序的不一致性,从而产生难以预料到的后果。
2.只能在React函数式组件或自定义Hook中使用Hook。