存在的意义
Hooks的作用在于完美过渡React中的类写法到函数式表示,因为我们知道React的函数式表示是不能使用生命周期的,Hooks可以代替React中的生命周期写法,这样就可以帮助完美过渡到函数式表示。这么做的意义是,类和生命周期的写法,不得不将不同的类互相联系起来,导致其中的业务逻辑会因为生命周期交错在一起而使得业务逻辑复杂难以维护
我对Hooks想要解决的情况可能有更深的感悟,因为原来技术栈是vue,vue2的写法相比react类的写法使得组件之间的混用显得异常困难,即使是利用mixin也没办法妥善地去对一些关键业务尽量复用封装,甚至有可能会因为组件祖孙逻辑缠绕过深而导致所谓的“回调地狱”的情况,vue3的解决方式便是借鉴了react的hooks写法,去暴露一些核心的api,使得代码逻辑可以不因为所谓固定的结构受到限制,可以更加灵活地复用其中的公共部分,也许这就是hooks最大的意义所在
State Hook
在React中我们将与视图相关的变量定义在state中,在React的类定义模式下,定义在constructor中,如下代码:
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 1
}
}
render() {
return (
<div>{this.state.count}</div>
);
}
}
我们知道,在React中,我们如果使用函数式表达,是没有构造函数的,所以React暴露了一个hook, useState去代替在constructor中定义state,如下代码:
import React, { useState } from 'react'
const Example = (props) => {
const [count, setCount] = useState(1);
return (
<div>{count}</div>
)
}
不难理解,这里我们传递给useState一个1的参数,这个对应count的值,useState会返回一个包含声明的变量以及其set方法的数组,这里我们使用解构去获得它,这个count与直接声明的普通的count变量最大的不同在于
我们声明了一个叫 count 的 state 变量,然后把它设为 0。React 会在重复渲染时记住它当前的值,并且提供最新的值给我们的函数。我们可以通过调用 setCount 来更新当前的 count。
没错,它的更新变化会与视图的渲染相关,如果是普通的变量,后面在变量变化的时候,视图并没办法捕捉到变量的变化,并做出响应。
Effect Hook
Effect Hook的存在其实就是为了替代类定义中使用的生命周期方法,提供一种在组件中进行副作用操作的方案
无需清除的effect
无需清除的effect的是指有的时候我们需要在react更新dom进行一些额外的代码,并且在执行完以后我们可以选择忽略它们,这些就是无需清除的effect,举个例子说明一下:
import React, { useEffect } from 'react';
function Example() {
useEffect(() => {
document.title = `You clicked ${count} times`;
})
}
这样就会在每次渲染之后,将document的title做一个修改,使用Effect Hook我们就不需要考虑“挂载”还是“更新”了,将会保证执行在每次渲染之后。
需要清除的effect
其实很简单,用于替代destroy的生命周期,只需要在无需清除的基础上加一个返回值即可
import React, { useEffect } from 'react';
function Example() {
useEffect(() => {
document.title = `You clicked ${count} times`;
return function() {
console.log('清除');
}
})
}
与更新的操作类似,清除也会在每次渲染之后执行,因为这个机制的原因,我们可以避免很多bug,因为不需要区分挂载和更新了,所有的监听清除会一一对应地在每次渲染之后执行
跳过不必要的effect以提高性能
上文我们提到,effect会在每次渲染之后都执行,但是实际上,我们并不一定需要每次渲染之后都执行effect的,有可能在满足一些条件,比如变量改变的情况下才执行effect,所以api额外提供了一个参数来实现这个情况,如下代码:
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // 仅在 count 更改时更新
像上面的例子,只有在渲染之后,对比count发生了改变才会执行effect,否则就会跳过这个effect来达到性能优化的目的
自定义hook
其实就是提取公共逻辑作为单独的工具类函数而已,唯一要注意的点是,自定义 Hook 必须以 “use” 开头,官方的解释是:
这个约定非常重要。不遵循的话,由于无法判断某个函数是否包含对其内部 Hook 的调用,React 将无法自动检查你的 Hook 是否违反了 Hook 的规则。
同时我们也要注意的是,自定义hook并不会共享调用位置的state,所以useState要与自定义hook一并封装,不然就会导致逻辑上意料之外的问题
其他
还有一些其他的hook,看了一下文档,都不是那么常用,后面需求需要再进一步学习加深印象