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 也就给了我们两个变量,我们其实可以随便给它们命名,这个数组中的两个变量是:

  1. 第一个变量是「状态值」,它有点像 this.state
  2. 第二个变量是一个更新「状态值」的方法,有点像 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, and componentWillUnmount.

前面的 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 了,好吗?

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,864评论 6 494
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,175评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,401评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,170评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,276评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,364评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,401评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,179评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,604评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,902评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,070评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,751评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,380评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,077评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,312评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,924评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,957评论 2 351

推荐阅读更多精彩内容