react hooks--概述

前言

Hook 是 React 16.8 的新增特性,它可以让我们在 不编写class的情况下使用state以及其他的React特性(比如生命周期)。

我们先来思考一下class组件相对于函数式组件有什么优势?比较常见的是下面的优势:

◼ class组件可以定义自己的state,用来保存组件自己内部的状态;

 函数式组件不可以,因为函数每次调用都会产生新的临时变量;

◼ class组件有自己的生命周期,我们可以在对应的生命周期中完成自己的逻辑;

 比如在componentDidMount中发送网络请求,并且该生命周期函数只会执行一次;

 函数式组件在学习hooks之前,如果在函数中发送网络请求,意味着每次重新渲染都会重新发送一次网络请求;

◼ class组件可以在状态改变时只会重新执行render函数以及我们希望重新调用的生命周期函数componentDidUpdate等;

 函数式组件在重新渲染时,整个函数都会被执行,似乎没有什么地方可以只让它们调用一次;

所以,在Hook出现之前,对于上面这些情况我们通常都会编写class组件。

在react中组件分为类组件和函数组件

类组件:

  • 通过class类去定义组件

  • 类组件有内部state状态,可以通过setState控制组件自身更新渲染

  • 类组件拥有自己的生命周期

    class App extends React.Componnet {
    constructor(props) {
    super(props);
    }

      click = () => {
          
      }
      
      render() {
          return (
          	<div onClick={this.click}>类组件</div>
          )
      }
    

    }

Class组件存在的问题

复杂组件变得难以理解:

 我们在最初编写一个class组件时,往往逻辑比较简单,并不会非常复杂。但是随着业务的增多,我们的class组件会变得越来越复杂;

 比如componentDidMount中,可能就会包含大量的逻辑代码:包括网络请求、一些事件的监听(还需要在componentWillUnmount中移除);

 而对于这样的class实际上非常难以拆分:因为它们的逻辑往往混在一起,强行拆分反而会造成过度设计,增加代码的复杂度;

难以理解的class:

 很多人发现学习ES6的class是学习React的一个障碍。

 比如在class中,我们必须搞清楚this的指向到底是谁,所以需要花很多的精力去学习this;

 虽然我认为前端开发人员必须掌握this,但是依然处理起来非常麻烦;

组件复用状态很难

 在前面为了一些状态的复用我们需要通过高阶组件;

 像我们之前学习的redux中connect或者react-router中的withRouter,这些高阶组件设计的目的就是为了状态的复用;

 或者类似于Provider、Consumer来共享一些状态,但是多次使用Consumer时,我们的代码就会存在很多嵌套;

 这些代码让我们不管是编写和设计上来说,都变得非常困难;

函数组件

  • 使用函数编写组件

  • 函数组件没有内部state,无法控制自身更新渲染,只能接收外部props数据来更新渲染

  • 函数组件没有生命周期

  • 函数式组件的命名:第一个字母必须大写

    function App() {

      function click() {
          
      }
      
      return (
          <div onClick={click}>函数组件</div>
      )
    

    }

Hooks概述

随着react版本的更迭,在react16.8版本,新增了hook特性,可以通过hook函数去开发函数组件,使函数组件内部拥有了state内部状态,以及模拟生命周期

Hook只能在函数组件中使用,不能在类组件,或者函数组件之外的地方使用!!!

  • Hooks:钩子、钓钩、钩住
  • HooksReact v16.8 中的新增功能
  • 作用:为函数组件提供状态、生命周期等原本 class 组件中提供的 React 功能
    • 可以理解为通过 Hooks 为函数组件钩入 class 组件的特性
  • 注意:Hooks 只能在函数组件中使用,自此,函数组件成为 React 的新宠儿

React v16.8 版本前后,组件开发模式的对比:

  • React v16.8 以前: class 组件(提供状态) + 函数组件(展示内容)
  • React v16.8 及其以后:
    1. class 组件(提供状态) + 函数组件(展示内容)
    2. Hooks(提供状态) + 函数组件(展示内容)
    3. 混用以上两种方式:部分功能用 class 组件,部分功能用 Hooks+函数组件

注意1:虽然有了 Hooks,但 React 官方并没有计划从 React 库中移除 class。

注意2:有了 Hooks 以后,不能再把函数组件称为无状态组件了,因为 Hooks 为函数组件提供了状态。

为什么要有 Hooks

两个角度:1 组件的状态逻辑复用 2 class 组件自身的问题

  1. 组件的状态逻辑复用:
    • 在 Hooks 之前,组件的状态逻辑复用经历了:mixins(混入)、HOCs(高阶组件)、render-props 等模式。
    • (早已废弃)mixins 的问题:1 数据来源不清晰 2 命名冲突。
    • HOCs、render-props 的问题:重构组件结构,导致组件形成 JSX 嵌套地狱问题。
  1. class 组件自身的问题:
    • 选择:函数组件和 class 组件之间的区别以及使用哪种组件更合适
    • 需要理解 class 中的 this 是如何工作的
    • 相互关联且需要对照修改的代码被拆分到不同生命周期函数中
      • componentDidMount -> window.addEventListener('resize', this.fn)
      • componentWillUnmount -> window.addEventListener('resize', this.fn)
  • 相比于函数组件来说,不利于代码压缩和优化,也不利于 TS 的类型推导
  • 语法上来说,函数组件学习成本会低一点,函数组件少了this指向和继承
  • 从组件的开发难易程度来说,函数组件相对于类组件来说难度低一点,函数组件少了this指向和继承
  • 类组件的开发基于面向对象方式开发,类与类之间通过继承来达到了一种依赖关系,这种继承的开发方式并不是最好的解决方案

正是由于 React 原来存在的这些问题,才有了 Hooks 来解决这些问题

hooks的优势

由于原来 React 中存在的问题,促使 React 需要一个更好的自带机制来实现组件状态逻辑复用。

  1. Hooks 只能在函数组件中使用,避免了 class 组件的问题
  2. 复用组件状态逻辑,而无需更改组件层次结构
  3. 根据功能而不是基于生命周期方法强制进行代码分割
  4. 抛开 React 赋予的概念来说,Hooks 就是一些普通的函数
  5. 具有更好的 TS 类型推导
  6. tree- - shaking 友 好,打包时去掉未引用的代码
  7. 更好的压缩

项目开发中,Hooks 的采用策略:

  • 不推荐直接使用 Hooks 大规模重构现有组件
  • 推荐:新功能用 Hooks,复杂功能实现不了的,也可以继续用 class
  • 找一个功能简单、非核心功能的组件开始使用 hooks

class 组件相关的 API 不用了,比如:

  • class Hello extends Component
  • componentDidMountcomponentDidUpdatecomponentWillUnmount
  • this 相关的用法

原来学习的内容还是要用的,比如:

  • JSX:{}onClick={handleClick}、条件渲染、列表渲染、样式处理等
  • 组件:函数组件、组件通讯
  • 路由
  • React 开发理念:单向数据流状态提升
  • 解决问题的思路、技巧、常见错误的分析等上
hook函数使用规则
  • 只在 React 函数中调用 Hook,不要在普通的 JavaScript 函数中调用 Hook
  • 只能在最顶层使用 Hook
  • 不要在循环,条件或嵌套函数中调用 Hook,确保总是在你的 React 函数的最顶层调用他们
  • 遵守这条规则,你就能确保 Hook 在每一次渲染中都按照同样的顺序被调用
  • 这让 React 能够在多次的 useStateuseEffect 调用之间保持 hook 状态的正确
  • 不要在class类组件中使用hook函数

hooks 的缺陷

计数器示例

类组件实现
import React, { PureComponent } from 'react'

export default class demoClassComponent extends PureComponent {
  constructor(props) {
    super(props)

    this.state = {
      counter: 0,
    }
  }

  increment() {
    this.setState({
      counter: this.state.counter + 1,
    })
  }

  decrement() {
    this.setState({
      counter: this.state.counter - 1,
    })
  }

  render() {
    const { counter } = this.state

    return (
      <div>
        <p>当前计数:{counter}</p>
        <button onClick={(e) => this.increment()}>+1</button>
        <button onClick={(e) => this.decrement()}>-1</button>
      </div>
    )
  }
}
函数组件实现
import { memo, useState } from 'react'

function DemoFuncClassComponent() {
  const [counter, setCounter] = useState(0)

  return (
    <div>
      <p>当前计数:{counter}</p>
      <button onClick={(e) => setCounter(counter + 1)}>+1</button>
      <button onClick={(e) => setCounter(counter - 1)}>-1</button>
    </div>
  )
}

export default memo(DemoFuncClassComponent)
相关推荐
Jason-河山2 小时前
「铭记历史 珍爱和平」勿忘9.18!
前端
国王不在家2 小时前
keyof和infer
前端
猿大撒2 小时前
Spring-data-redis
前端·bootstrap·html
帅过二硕ฅ3 小时前
uniapp点击跳转到对应位置
前端·javascript·uni-app
正小安5 小时前
URL.createObjectURL 与 FileReader:Web 文件处理两大法宝的对比
前端·javascript
赵广陆6 小时前
SprinBoot+Vue宠物寄养系统的设计与实现
前端·vue.js·宠物
A黄俊辉A6 小时前
vue3中把封装svg图标为全局组件
前端·javascript·vue.js
老贾爱编程6 小时前
VUE实现刻度尺进度条
前端·javascript·vue.js
F2E_Zhangmo6 小时前
vue如何做到计算属性传参?
前端·javascript·vue.js
繁依Fanyi7 小时前
828华为云征文|华为Flexus云服务器搭建OnlyOffice私有化在线办公套件
服务器·开发语言·前端·python·算法·华为·华为云