React hooks 简单介绍

想第一时间获取我的最新文章,请关注公众号: 技术特工队

技术特工队

React Hooks 产生的原因

在平时的React开发中,我们常用的是使用 Class 来封装一个组件,这也是我们常常使用的方法,看似使用起来很好用,很方便的,那有没有一些让你不舒服的地方呢? 让我们往下看。

改造成本大

封装一个组件常常使用Class类来进行,如果够简单很普通的组件,就只有一个render函数,通常这种会被直接写成函数组件,如下所示:

1
2
3
export function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}

上面的组件其实等效于下面的class

1
2
3
4
5
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}

但如果我们使用的函数式组件,这时候如果需要在组件内不得不加状态时,我们就必须把函数式组件改造为class 类型的组件,才能满足我们的需求,如果对于很多的函数式组件,那这是致命的,会产生很大的工作量及不稳定的因素在里面了。所以想要复用一个有状态的组件太麻烦了!

业务不聚焦

在来看一个组件,即使这个组件比较简单,但代码较多比较复杂了,需要定义 构造函数,响应函数,render函数,生命周期函数等等,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import React, { Component } from "react";

export default class Button extends Component {
constructor() {
super();
this.state = { buttonText: "Click me, please" };
this.handleClick = this.handleClick.bind(this);
}
componentDidMount() {
// add back key Listern
}

componentWillUnmount() {
// remove back key listener
}
handleClick() {
this.setState(() => {
return { buttonText: "Thanks, been clicked!" };
});
}
render() {
const { buttonText } = this.state;
return <button onClick={this.handleClick}>{buttonText}</button>;
}

在这个组件中componentDidMountcomponentWillUnmount 按逻辑应该是add 和 remove 同一个业务的listener,但它的业务被分到两个方法中,若这种方法较多,就会比较零散,且这两个生命周期中包含的业务就比较复杂了,所以这也是一个较大的问题。

复用性较复杂

比如一个通用的组件中包含不同的子组件,可能需要使用到 Render Props高阶组件 来进行组合,但是这样使用的成本实际上比较高的。

React Hooks 什么

React Hooks 的意思是,组件尽量写成纯函数,如果需要外部功能和副作用,就用钩子把外部代码”钩”进来。 React Hooks 就是那些钩子。

下面介绍的 useState, useEffect, useRef, useContext 等都为官方提供的一些常用的hooks方法,基本上这几类都能解决大部分的函数式组件的需求。
下面我们大概进行介绍

useState

useState 是官方提供的一个函数式组件中管理 State
的hook函数,相当于之前的 this.state,

1
2
3
4
// count为定义的状态为 count
// setCount 为提供的改变count属性的方法
// 0 为属性 count 的默认值,当然也可以为对象
const [count, setCount] = useState(0);

上面的代码就相当于之前state的下面写法:

1
2
3
this.state = { 
count: 0,
}

对于多个方法State的使用useState写法如下:

1
2
const [count, setCount] = useState(0);
const [age, setAge] = useState(0);

注意: 必须按照顺序写在函数最外层执行,不能使用 if else 进行条件判断,

如果要更新state的值,则使用素组中第二个方法调用setCount 或者 setAge方法进行更新,如下:

1
2
3
4
5
6
setAge(18) 

// 等价于
this.setState({
age: 18
})

这样整体上看,也是更加的简洁了。

useEffect

上面有了state,但是在class中,还会有生命周期的函数,对于函数式组件,则没法直接表示生命周期,所以就有了useEffect
useEffect 代表 componentDidMount and componentDidUpdate and componentWillUnmount, 当然代表不同的函数肯定有不同的写法。基本如下:

1
2
3
4
5
6
7
8
9
10
useEffect(() => {
document.title = 'use effect demo'
})
// 以上代码就相当于在 `componentDidMount` and `componentDidUpdate` 中执行方法中的语句。等同于如下:
componentDidMount() {
document.title = `use effect demo`
}
componentDidUpdate() {
document.title = `use effect demo`
}

那么要实现componentWillUnmount 如何处理呢? 方法如下:

1
2
3
4
5
6
7
8
useEffect(() => {
// foreample add listener
API.addListener(*)
// 这里返回就是清除操作的函数方法
return () => {
API.removeListener(*)
}
})

通过在函数中返回一个析构的方法,来释放相对应的资源。但是上面这种会在每次render渲染的收都会执行一次add,在下次渲染时,先执行remove,然后在进行add,所以导致每次render时会造成很多不必要的方法执行,那当然 React 官方也知道问题点了,所以就有了与某个state状态绑定的关系,写法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 只会在count变化的时候才会执行此方法。
useEffect(() => {
document.title = `use effect demo count = ${count}`
}, [count])

// 在userId变化的时候,重新添加listener,并移除原来的
useEffect(() => {
// foreample add listener
API.addListener(*, userId)
// 这里返回就是清除操作的函数方法
return () => {
API.removeListener(*, userId)
}
}, [userId])

useEffect 这一个会是经常用到的方法。掌握了她,后面其他的几个也就很容易理解和掌握了。

useRef

useRef 主要是对一些控件操作时,需要用到的,比如说textinput焦点等,这个使用和 useState类似 ,下面举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
function LoginView() {
const input = useRef(null)
const forceInpput = () => {
input.current.force()
}
return () => {
<View>
<TextInput ref={input} />
<Button onpressed={forceInput} />
</view>
}
}

这样可以直接拿到函数中空间的ref对象,进行相应控制操作。

其他几种React的使用

参考: https://zh-hans.reactjs.org/docs/hooks-reference.html

自定义React hooks

对于可以提取复用的组件,则可以定义一起通用的React custom hooks ,这里其实也是对 上面几种react hooks的组合使用,这里就不多介绍了,具体参考
https://zh-hans.reactjs.org/docs/hooks-custom.html

React Hook 总结

使用React hook模式代码看起来确认很精简,看起来也很舒服,当前如果要使用这一套还必须团队的成员一起进行执行。对于之前已经时间的 Component 就没必要进行重写了,实际上他们是一样的效果。

参考资料

https://zh-hans.reactjs.org/docs/hooks-intro.html

WangXin wechat
欢迎订阅我的微信公众号,第一时间获取最新文章!
坚持原创技术分享,您的支持将鼓励我继续创作!