什么是 React Hooks
Hooks 是React 16.8 新增的特性,在你不需要写class 组件的情况下,就赋予了函数式组件 state 状态管理及生命周期函数的特性
Hooks的优势
all in 函数式编程
在你编写React应用时,不需要再纠结在 函数式组件、class 类组件、高阶组件、render props 之间的切换
- 开发人员首先需要根据页面UI及业务场景,对页面进行抽象和组件拆分,做出人为划分:
- 需要逻辑状态的使用
class组件 - 纯UI展示的使用函数式组件
- 需要逻辑状态的使用
- 哪天需求有变动,需要原来的函数式组件需要状态管理,你需要决定是否需要把状态提升到父级组件 或者 将原函数式组件重写为
class组件 - 逻辑复用需要考虑使用 高阶组件 还是 render props
- 组合优于继承的理念,使用class类组件的继承会使得应用更复杂,难以维护,同时复用性降低
有了Hooks,以上问题统统解决,使用Hooks + 函数式组件可以完成满足所有场景
class 类组件相关逻辑的割裂、不相关逻辑的耦合
- class 类组件,各个阶段的声明周期函数,往往把相关的逻辑割裂开
比如你要在
componentDidMount中设置定时器,在componentWillUnmount中移除定时器;你要在componentDidMountcomponentDidUpdate中写重复的逻辑 - class 类组件,
componentDidMount钩子函数中往往需要将不相关的逻辑都写在这一个钩子函数中
import React from 'react'
class Timer extends React.Component{
constructor(props){
super(props)
this.state = {
second: 0,
count: 0
}
this.handleClick = this.handleClick.bind(this)
}
handleClick(){
this.setState(state => {
return {
count: state.count+1
}
})
}
conponentDidMount(){
document.title = `You clicked ${this.state.count} times`; // 不相关的两个逻辑写到一起
this.interval = setInterval(() => {
this.setState(state => {
return {
count: state.second+1
}
})
}, 1000)
}
componentDidUpdate(){
document.title = `You clicked ${this.state.count} times`; // 相同的逻辑在conponentDidMount中也写了一遍
}
componentWillUnmount(){
clearInterval(this.interval) // 处理定时器的逻辑被分散到不同生命周期函数中
}
render(){
return (
<>
<div>Second: {this.state.second}</div>
<button onClick={this.handleClick}>count: {this.state.count}</button>
</>
)
}
}
使用hooks,可以将相关逻辑都放在一个useEffect中,不相关逻辑放在各自 useEffect 中
import { useState, useEffect } from 'react'
function Timer(){
const [second, setSecond] = useState(0)
const [count, setCount] = useState(0)
useEffect(() => {
document.title = `You clicked ${count} times`;
},[count])
useEffect(() => {
const interval = setInterval(() => {
setSecond(second => second+1)
}, 1000)
return () => clearInterval(interval)
})
return (
<>
<div>Second: {second}</div>
<button onClick={setCount(count+1)}>count: .count}</button>
</>
)
}
提高状态逻辑的复用性
- 在Hooks之前,我们往往通过HOC、render props的方式来完成逻辑复用,但是HOC、render props等方法都会遇到多层嵌套地狱的问题,当嵌套多层时可能会存在props的传值冲突的问题、排查线上问题时某一个state无法快速辨别到底是哪一层高阶组件传进来等问题
- 而基于Hooks,我们可以把可复用的状态逻辑抽离到一个函数中作为自定义Hooks,通过多个Hooks的组合完成复杂逻辑共享
- 多处复用同一个Hooks时,只是复用Hooks的处理状态的逻辑,每一个Hooks中的状态都是独立的
const { useState, useEffect } from 'react'
function useTimer(){
const [second, setSecond] = useState(0)
useEffect(() => {
const interval = setInterval(() => {
setSecond(second => second + 1)
}, 1000)
return () => clearInterval(interval)
})
return second
}
function Timer1(){
const second = useTimer()
return <div>second: {second}</div>
}
function Timer2(){
const second = useTimer()
return <div>second: {second}</div>
}
组件多状态需求
函数式组件结合hooks,组件的每一次渲染获得的state都是独立的,可以实现多种状态的组件需求,而class类组件中访问的this永远是指向最新的实例状态
function Counter() {
const [count, setCount] = useState(0);
const alertMe = () => {
setTimeout(() => {
console.log(`You clicked ${count} times`);
}, 3000);
}
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
<button onClick={alertMe}>
Alert me
</button>
</div>
);
}
先点击Alert me,开启3秒定时器,然后快速点击Click me3次,页面计数累加到3,3s后执行定时器回调,打印的是 You clicked 0 times