扔掉你的Class吧,Hooks太香了(一)

隆儿
• 阅读 1499

简介

Hook 是React16.8中新增的特性,它可以让你不编写class组件的情况下使用诸如state,生命周期等特性。

动机

在组件之间复用状态逻辑很难

为了解决这类问题,也有出现过一些解决方案,如render props高阶组件Context等,它们都会导致组件树形成嵌套地狱(有点像回调函数和flutter的写法)。

有了 Hook 之后,就可以从组件中提取状态逻辑,使得这些逻辑可以单独测试并复用。Hook 使你在无需修改组件结构的情况下复用状态逻辑

复杂组件变得难以理解

随着业务扩张,组件内的逻辑状态和副作用也越来越多。我们在写 class 组件时,通常会将数据的获取放到compoentDidMountcomponentDidUpdate中,涉及到定时器或者数据订阅时,还需要在生命周期函数compoentWillUnmount去清除定时器或者取消数据订阅。这使得完全不相关的代码组合到一起,很容易产生bug,并且导致逻辑不清晰。

为了解决这个问题,Hook 将组件中相互关联的部分拆分成更小的函数(比如设置订阅或请求数据),而并非强制按照生命周期划分

难以理解的 class

在之前,如果你要使用诸如state生命周期等特性,就必须引入 class 组件,如果你要使用这些就必须花时间去理解 JavaScript 中this的工作方式。

为了解决这些问题,Hook 使你在非 class 的情况下可以使用更多的 React 特性

概览

Hook 可以分为内置 Hook自定义 Hook

内置 Hook 有:

  • useState
  • useEffect
  • useContext
  • useReducer
  • useCallback
  • useMome
  • useRef
  • useImperativeHandle
  • useLayoutEffect
  • useDebugValue

自定义 Hook就是将上述内置 Hook进行组合,导出为一个以use开头的函数。


这里先写一个基于class的 Counter组件,后面让我们来用Hook将它进行改造。

`import React from 'react'
class Counter extends React.Component {
  constructor(props) {
    super(props)
    this.state = { count: 0 }
    this.setCount = this.setCount.bind(this)
  }
  setCount() {
    this.setState({
      count: this.state.count + 1
    })
  }
  
  render() {
    return (
      <>
        <h2>{ this.state.count }</h2>
        <button onClick={ this.setCount }>+</button>
      </>
    )
  }
}
`

useState

让我们先来看一个最基础也同样重要的 Hook,现在我们开始改造上面的class组件。
  • 首先将class组件转为function组件,也就是函数式组件

`- class Counter extends React.Component {}
+ function Counter() {}
`

  • 接下来让我们将state等相关代码删掉,改用useStateHook,因为此处改动较多,直接上最终代码

`import React, { useState } from 'react'
const Counter = () => {
  // 数组解构语法
  // 声明一个count变量,并声明一个setCount函数用于改变count的值
  const [count, setCount] = useState(0)
  
  return (
    <>
      <h2>{ count }</h2>
      <button onClick={ () => setCount(count + 1) }>+</button>
    </>
  )
}
`

乍一看代码简洁了很多,这难道不正是我们想要的嘛。(Hook 真香)

如果我们有多个state变量,可以写成下面这种形式

`const [count, setCount] = useState(0)
const [num, setNum] = useState(0)
const [name, setName] = useState('')
...
`

如果本次更新依赖于上一次的state值,可以这么写,此时setCount接收一个函数作为参数

`const [count, setCount] = useState(0)
const handleClick = () => {
  setCount(prev => prev + 1)
}
<button onClick={ handleClick }>+</button>
`

useEffect

useEffect 可以让你在函数式组件执行一些副作用操作,它接收两个参数,第一个参数为必选的副作用函数,第二个为可选的参数(它是副作用函数执行的依赖项数组)

还是刚才的例子,如果我们希望组件更新后执行一些副作用,比如打印当前count变量的值,又或者改变当前页面的 title

``// ...
const [count, setCount] = useState(0)
const [num, setNum] = useState(0)
useEffect(() => {
  console.log(当前count值,${count})
  document.title = 当前count值,${count}
})
// ...
``

上面的代码我们可以看到我们并没有添加第二个可选参数,这意味着,只要组件内状态发生改变(不仅仅是count,甚至num发生改变时),这个副作用函数都会执行。如果我们希望副作用函数只在 count 改变时候执行,这时候我们的第二个参数就派上用场了()

``// ...
// 当前effect函数只依赖于 count 的改变,在 num 改变的时候并不会被执行
// 相当于 class 组件中的 compoentDidMount 和 componentDidUpdate
useEffect(() => {
  console.log(当前count值,${count})
  document.title = 当前count值,${count}
}, [count])
// ...
``

如果我们仅仅希望副作用函数在组件挂载时候执行(compoentDidMount

``// useEffect 约定,在第二个参数传递空数组时,当前副作用函数只在组件挂载时被执行
useEffect(() => {
  console.log(当前count值,${count})
  document.title = 当前count值,${count}
}, [])
``

有些时候我们可能会用到定时器,比如每秒钟更新一次时间

`const [time, setTime] = useState(new Date())
const timer = null
useEffect(() => {
  timer = setInterval(() => {
    setTime(new Date())
  }, 1000)
})
`

现在的代码有一个问题,想必大家都知道,那就是timer 没有被清除,我们在工作中会遇到很多这种场景,那么我们应该怎么去清除 timer 呢,答案是useEffect的第一个参数返回一个函数,这个被返回的函数会在组件被卸载时候自动被执行,可以清除诸如定时器之类的东西

`const [time, setTime] = useState(new Date())
const timer = null
useEffect(() => {
  timer = setInterval(() => {
    setTime(new Date())
  }, 1000)
  
  // 类似于 compoentWillUnMount
  
  // 当然这里也可以是一个具名函数
  return () => {
    clearInterval(timer)
    timer = null
  }
})
`

点赞
收藏
评论区
推荐文章
海军 海军
4年前
React Hook丨用好这9个钩子,所向披靡
ReactHook指南什么是Hook?Hook是React16.8的新增特性。它可以让你在不编写class的情况下使用state以及其他的React特性。Hook本质上就是一个函数,它简洁了组件,有自己的状态管理,生命周期管理,状态共享。useStateuseEffectuseContextus
Souleigh ✨ Souleigh ✨
4年前
Hook 简介 – React
Hook简介_Hook_是React16.8的新增特性。它可以让你在不编写class的情况下使用state以及其他的React特性。importReact,{useState}from'react';functionExample(){//声明一个新的叫做“count”的sta
Souleigh ✨ Souleigh ✨
4年前
Hook 规则 – React
Hook规则_Hook_是React16.8的新增特性。它可以让你在不编写class的情况下使用state以及其他的React特性。Hook本质就是JavaScript函数,但是在使用它时需要遵循两条规则。我们提供了一个linter插件(https://www.npmjs.com/package/
亚瑟 亚瑟
4年前
自定义 Hook – React
自定义Hook_Hook_是React16.8的新增特性。它可以让你在不编写class的情况下使用state以及其他的React特性。通过自定义Hook,可以将组件逻辑提取到可重用的函数中。在我们学习时,我们已经见过这个聊天程序中的组件,该组件用于显示好友的在线状态:importReact,{useSta
亚瑟 亚瑟
4年前
Hook API 索引 – React
HookAPI索引_Hook_是React16.8的新增特性。它可以让你在不编写class的情况下使用state以及其他的React特性。本页面主要描述React中内置的HookAPI。如果你刚开始接触Hook,那么可能需要先查阅。你也可以在章节中获取有用的信息。基础Hook
亚瑟 亚瑟
4年前
使用 Effect Hook – React
使用EffectHook_Hook_是React16.8的新增特性。它可以让你在不编写class的情况下使用state以及其他的React特性。_EffectHook_可以让你在函数组件中执行副作用操作importReact,{useState,useEffect}from'reac
亚瑟 亚瑟
4年前
Hook 规则 – React
Hook规则_Hook_是React16.8的新增特性。它可以让你在不编写class的情况下使用state以及其他的React特性。Hook本质就是JavaScript函数,但是在使用它时需要遵循两条规则。我们提供了一个来强制执行这些规则:只在最顶层使用Hook不要在循环,条件或嵌套函数中调用Hoo
亚瑟 亚瑟
4年前
使用 State Hook – React
使用StateHook_Hook_是React16.8的新增特性。它可以让你在不编写class的情况下使用state以及其他的React特性。中使用下面的例子介绍了Hook:importReact,{useState}from'react';functionExample(){//
可莉 可莉
3年前
10分钟教你手写8个常用的自定义hooks
https://juejin.im/post/5e57d0dfe51d4526ce6147f2前言Hook是React16.8的新增特性。它可以让你在不编写class的情况下使用state以及其他的React特性。本文是一篇以实战为主的文章,主要讲解实际项目中如何使用hooks以及一些最佳实践,不会一步步再介
Stella981 Stella981
3年前
React 新特性 React Hooks 的使用
关注前端技术专栏,回复“资源”免费领取全套视频教程正文什么是Hooks?Hooks是React16.8的新增特性。它可以让你在不编写class的情况下使用state以及其他的React特性。是一些可以让你在函数组件里“钩入”Reactstate及生命周期等特性的函数。Ho
美凌格栋栋酱 美凌格栋栋酱
5个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(