React Hooks 不完全指南
Photo by Ngọc Thuận on Unsplash人生真正的本质不是希望,而是意义。人总是会死的,希望总是会破灭。但,只要你认为你人生的每一天都是有意义的,你才能够去面对你经历的所有苦难。
React 前段时间发布了 Hooks 这个新的特性,虽然还只是个提案,但是很多人都表示很看好它,今天我们就来了解一下 React Hooks。
准备工作
我们先使用 create-react-app
新建一个项目:
$ npm install -g npx
$ npx create-react-app hooks
由于 React Hooks 还只是个 RFC 草案,所以我们还不能在正式版本中使用它,需要安装对应的 alpha 版本才可以:
$ cd hooks
$ npm install -S react@16.7.0-alpha.2 react-dom@16.7.0-alpha.2
$ npm run start
一个简单的例子
我们可以打开项目,在 /src
下新建一个 Counter.js
文件:
import React, { useState } from 'react';
export function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<h1>{count}</h1>
<button onClick={() => setCount(count + 1)}>没事走俩步</button>
</div>
)
}
怎么样?是不是看出了点什么?让我们把这个组件放到 App.js
下看看效果~
import { Counter } from './Counter';
class App extends Component {
render() {
return (
<div className="App">
<Counter />
</div>
)
}
}
好吧,这其实就是个最简单的计数器组件,并没有什么了不起的。如果是在原来,我们会怎么写呢?
import React from 'react'
export class AnotherCounter extends Component {
constructor() {
super()
this.state = { count: 0 }
}
increment = () => {
this.setState({ count: this.state.count + 1})
}
render() {
return (
<div>
<h1>{this.state.count}</h1>
<button onClick={ this.increment }>你跺你也麻</button>
</div>
)
}
}
为了使用 state
我们必须使用 class component,所以你肯定已经明白了——什么是 React Hooks?
Hooks let you use React features without writing a class!
哦!这个叫做「钩子」的东西让我们再也不用写 class component
啦!
PS:也别担心,React 官方并没有不鼓励使用类组件的意思,只是给我们多提供了一种写组件的方式~
useState
好了,知道了 Hooks 是什么,让我们再回过头看看之前例子的代码吧!你一定对这个 useState
感到很好奇,它是怎么做到让 functional component
做到和 class component
一样的事情的呢?
我们其实可以看到,在 useState
方法前面,我们使用了数组解构的语法,其实 useState
也就给了我们两个变量,我们其实可以随便给它们命名,这个数组中的两个变量是:
- 第一个变量是「状态值」,它有点像
this.state
- 第二个变量是一个更新「状态值」的方法,有点像
this.setState
然后,我们传递给 useState
方法的其实是我们想要的「初始状态值」,在这里我们传了一个 0
作为 count
的初始值,相当于在构造函数中 this.state = { count: 0 }
的作用。
就是这么简单!
多个 State Hooks
你可能会想,我的组件可定不会那么简单,它的 state
远比这里的 count
多得多,要怎么使用多个 state
并管理它们呢?
看看下面的代码,你会发现原来事情那么简单!
import React, { useState } from 'react';
function AllTheThings() {
const [count, setCount] = useState(0);
const [books, setBooks] = useState([{ name: 'Common Stock Uncommon Profit', author: 'Philip A. Fisher' }])
const [coupon, setCoupon] = useState(null);
return <div>{/_ use all those things here _/}></div>;
}
我只能说,一目了然,可以说是相当的简洁明了了~
useEffect
除了 state
,我们使用 class component
的原因其实还有一个——生命周期函数。
既然说了,Hooks 是让你能够不用 class component
就使用 React 特性的一种解决方案,那么对于组件生命周期的管理,Hooks 是怎么做到的呢?
Effects are similar to
componentDidMount
,componentDidUpdate
, andcomponentWillUnmount
.
前面的 useState
我们能理解,它能使用 state
,那这边的 useEffect
为啥叫这个名字呢?其实这些生命周期都是用来处理一些副作用的(side-effects),例如:
- 获取数据
- 手动操作 DOM
- 订阅一个流(RxJS)
所以我们把它称作 useEffect
,意思是用来管理这些副作用的地方。
好的,说了那么多,让我们来看看具体怎么使用它吧~
componentDidMount
一般在这个生命周期里,我们会做一些请求数据、操作DOM或者订阅流的操作,对应的使用 useEffect
的方法也很简单,
function DoSomethingCrazy() {
useEffect(() => {
console.log('great expectation');
document.title = 'What a long, strange trip it\'s been'
})
}
只需要给 useState
传递一个想要在此时执行的函数就可以了。
componentDidUpdate
这也是一个经常使用的生命周期,通常会需要在在 state
发生改变的时候,做一些副作用的操作,我们可以这么写:
// only run if count changes
useEffect(
() => {
// run here if count changes
},
[count]
);
componentWillUnmount
在即将 unmount
的时候,我们通常需要对之前订阅的流进行解除:
useEffect(() => {
UserAPI.subscribeToUserLikes();
// unsubscribe
return () => {
UserAPI.unsubscribeFromUserLikes();
}
});
你看,多么简单!
让我们把 useState 和 useEffect 整合起来
我们创建一个 GithubUsers.js
的组件,我们需要通过 API 获取 github 的一些随机的用户,并把他们展示在页面上。过去,我们需要使用类组件去做这些事情,现在直接使用函数组件就能完全搞定啦!
import React, { useState } from 'react';
export function GithubUsers() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch('https://api.github.com/users')
.then(response => response.json())
.then(data => {
setUsers(data);
});
}, []); // 这里是个空数组,因为我们不需要每次更新的时候都做这个操作
return (
<div className="section">
{users.map(user => (
<div key={user.id} className="card">
<h5>{user.login}</h5>
</div>
))}
</div>
);
}
好啦,快去和小伙伴炫耀你已经学会 React Hooks 了吧!😜
小结
React 的 state hooks 和 effect hooks 可以说是非常棒的新特性了,它不仅让我们知道 React 的团队始终没有停下前进的脚步,而且这些新的特性也会让新加入 React 的同学上手起来更加简单和轻松~
所以现在,不要再问我这个组件是写成 stateless functional component
还是 stateful class component
了,好吗?