React Hooks 入门基础(详细使用)

Posted 卡尔特斯

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React Hooks 入门基础(详细使用)相关的知识,希望对你有一定的参考价值。

一、简介

  • hooks 的本质:一套能够使函数组件更强大,更灵活的 “钩子”

  • React 体系里组件分为 类组件函数组件

    • 经过多年的实战,函数组件是一个更加匹配 React 的设计理念 UI = f(data),也更有利于逻辑拆分与重用的组件表达形式,而先前的函数组件是不可以有自己的状态的,为了能让函数组件可以拥有自己的状态,所以从react v16.8 开始,Hooks 应运而生。

    • 有了 hooks 之后,为了兼容老版本,class 类组件并没有被移除,俩者都可以使用。

    • 有了 hooks 之后,不能在把函数成为无状态组件了,因为 hooks 为函数组件提供了状态。

    • hooks 只能在函数组件或者自定义 hook 中使用,不能嵌套if/for/其他函数中react 会按照 hooks 的调用顺序识别每个 hook)。

  • hooks 解决了什么问题?

    • 组件的逻辑复用

      hooks 出现之前,react 先后尝试了 mixins 混入,HOC 高阶组件,render-props 等模式,但是都有各自的问题,比如 mixin 的数据来源不清晰,高阶组件的嵌套问题等等

    • class 组件自身的问题

      class 组件就像一个厚重的 战舰 一样,大而全,提供了很多东西,有不可忽视的学习成本,比如各种生命周期,this 指向问题等等,而更多时候需要的是一个轻快灵活的 快艇

  • hooks 让函数组件拥有了类组件的特性,例如组件内的状态、生命周期等,常用的有:

二、useState 使用

  • 基础案例

    import React,  useState  from "react";
    
    // 函数组件
    function Sub () 
      // 参数:状态初始值(传入 0 表示该状态的初始值为 0)
      // 返回值:数组(包含两个值:1、状态值(state)2、修改该状态的函数(setState))
    
      // 状态值名字可以自定义吗?可以自定义保持语义化
      // 返回值的顺序是否可以替换?不可以,第一个就是数据状态,第二个就是修改数据的函数
    
      // 组件的更新过程 与 当调用 setCount 的时更新过程:
    
      // 》首次渲染
      // 首次被渲染的时候,组件内部的代码会执行一次
      // 其中 useState 也会跟着执行,这里重点注意,初始值只在首次渲染时生效
    
      // 》更新渲染,调用 setCount 整个 app 中代码都会更新
      // 1、app 组件会再次渲染,这个函数会再次执行
      // 2、useState 再次执行,得到新的 count 值不是 0 而是修改之后的 1,模版会用新值渲染
      const [count, setCount] = useState(0)
      // 可以通过输出 count 验证
      console.log(count)
    
      // useState 可以执行多次
      const [list, setList] = useState([])
    
      // 点击方法
      function touchButton () 
        // 函数中不能写,会报错的
        // const [flag, setFlag] = useState(true)
        // + 1
        setCount(count + 1)
      
    
      return (
        <button onClick=touchButton>count</button>
        // <button onClick=() => setCount(count + 1)>count</button>
      )
    
    
    class App extends React.Component 
      render () 
        return (
          <div>
            <Sub></Sub>
          </div>
        )
      
    
    
    export default App
    
  • 函数方式

    import React,  useState  from "react";
    
    function getDefaultValue () 
      // 耗时操作
      for (let index = 0; index < 20000; index++) 
      
      // 返回结果
      return 10
    
    
    // 函数组件
    function Sub (props) 
      const [count, setCount] = useState(() => 
        // return props.count
        return getDefaultValue()
      )
      return (
        <button onClick=() => setCount(count + 1)>count</button>
      )
    
    
    class App extends React.Component 
      render () 
        return (
          <div>
            <Sub count=10></Sub>
          </div>
        )
      
    
    
    export default App
    

二、useEffect 使用

  • 理解函数副作用,什么是副作用?

    副作用是相对于主作用来说的,一个函数除了主作用,其他的作用就是副作用。对于 React 组件来说,主作用就是根据数据(state/props)渲染 UI,除此之外都是副作用。

  • 常见的副作用

    • 数据请求 ajax 发送

    • 手动修改 dom

    • localstorage 操作

    • useEffect 函数的作用就是为 react 函数组件提供副作用处理的!

  • 简单案例:

    import React,  useEffect, useState  from "react";
    
    // 函数组件
    function Sub () 
      const [count, setCount] = useState(0)
      // 例如:count 的主作用就是更换按钮中的内容,但是当需要用到它的副作用时,需要在 useEffect 函数中实现它副作用效果
      useEffect(() => 
        console.log('副作用函数调用了')
        // 副作业函数会每次数据变化都执行,默认是全部属性的副作用都会调用该函数,可以指定
        // 例如:当它初始化或变化时设置为网页标题,这就是副作业
        document.title = count
      )
      return (
        // 这是 count 的主作用
        <button onClick=() => setCount(count + 1)>count</button>
      )
    
    
    class App extends React.Component 
      render () 
        return (
          <div>
            <Sub></Sub>
          </div>
        )
      
    
    
    export default App
    
  • 添加空数组,只在组件首次渲染时执行一次

    useEffect(() => 
        console.log('副作用函数调用了')
        document.title = count
    , [])
    
  • 指定属性副作业执行,首次渲染时也会执行

    // 函数组件
    function Sub () 
      const [count, setCount] = useState(0)
      const [name, setName] = useState('dzm')
      // 指定 count/name 会有副作用回调,首次渲染也会回调
      useEffect(() => 
        console.log('副作用函数调用了')
        document.title = count
        // 此时什么时候会执行副作用函数?初始化 + count/name被修改时都会执行
      , [count, name])
      
      // 可以写多个副作用函数
      // useEffect(() => 
      //   console.log('count 副作用函数调用了')
      // , [count])
      // useEffect(() => 
      //   console.log('name 副作用函数调用了')
      // , [name])
      
      return (
        <>
          <button onClick=() => setCount(count + 1)>count</button>
          <button onClick=() => setName('test')>name</button>
        </>
      )
    
    
  • 注意:useEffect 回调函数中用到的数据(比如: count),也就是依赖数据,就应该出现在依赖项数组中,如果不添加依赖项会有 bug 出现,就算不是通过 useState 创建的属性也需要添加到数组中。

  • 清理副作用

    使用场景:在组件被销毁时,如果有些副作用操作需要被清理,就可以使用这种方式(比如常见的 定时器)。

    如果想要清理副作用,可以在副作用函数中的末尾 return 一个新的函数,在新的函数中编写清理副作用的逻辑,注意执行时机为:

    • 组件卸载时自动执行

    • 组件更新时,下一个 useEffect 副作用函数执行之前自动执行

    import  useEffect, useState  from "react"
    
    const App = () => 
      const [count, setCount] = useState(0)
      useEffect(() => 
        const timer = setInterval(() => 
          setCount(count + 1)
        , 1000)
        return () => 
          // 用来清理副作用的事情
          clearInterval(timer)
        
      , [count])
      return (
        <div>count</div>
      )
    
    
    export default App
    

入门React 17 + Vite + ECharts 实现疫情数据可视化「03 学习 React Hooks」

往期文章目录:

学习 React Hooks

在上一篇 React 17 + Vite + ECharts 实现疫情数据可视化「02 快速搭建项目」 中我们进行了项目的快速搭建,非常高兴能与大家在第 3 篇相见,本篇我们将教大家一些基础的 React 语法,由于本项目是 React 17 版本,因此全局写法采用 React Hooks。

本篇将给大家介绍两个非常重要又常见的两个 Hook,一个是 useState,另外一个是 useEffect,其它的 Hook 暂时不介绍哈,目前的项目版本还不是很需要。思维导图如下,给本文「点赞+评论+关注」三连,支持一下博主哈。

介绍 React

老规矩,先放上 React 官方中文文档 ,以官网最新为准哈,目前我看到的官方版本是 v17.0.2 ,据说 React 18 要来了,快学不动了

以官网简单介绍来说,React 就是:

用于构建用户界面的 JavaScript 库

React 特点

引用自 React 官方中文文档

  • 声明式

    React 使创建交互式 UI 变得轻而易举。为你应用的每一个状态设计简洁的视图,当数据变动时 React 能高效更新并渲染合适的组件。

    以声明式编写 UI,可以让你的代码更加可靠,且方便调试。

  • 组件化

    构建管理自身状态的封装组件,然后对其组合以构成复杂的 UI。

    由于组件逻辑使用 JavaScript 编写而非模板,因此你可以轻松地在应用中传递数据,并保持状态与 DOM 分离。

  • 一次学习,跨平台编写

    无论你现在使用什么技术栈,在无需重写现有代码的前提下,通过引入 React 来开发新功能。

    React 还可以使用 Node 进行服务器渲染,或使用 React Native 开发原生移动应用。

知晓了 React 相关特点,下面由我自己来总结一下吧,说说一些个人感悟:

首先是声明式,这个让我们在编写代码的时候会更直观,就好像我和 React 进行协作一样。

其次是组件化,这个应该很好理解,可以将复杂的视图进行拆分,并且对于某一块共同的视图可以进行复用,这样就做到了「高内聚低耦合」特点。

最后是一次学习,随处编写,这个主要靠虚拟 DOM 来保证实现,其实最开始想到的是 Java 语言,通过虚拟机可以在不同地方使用,而 React 通过虚拟 DOM,使得适用的范围更广了,比如做客户端、网页版、移动端这些都能适用。

介绍 React Hook

先来看看 Hook 简介

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。

还记得 20 年大三的时候,刚接触 React,那个时候学习 React 大家都觉得很难,我自己使用也是那么觉得,尤其是一些重复性操作,比如创建一个文件,要写上大概如下代码:

class HelloMessage extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }
  render() {
    return (
      <div>
        Hello {this.props.name}
      </div>
    );
  }
}

那么,既然有这么多重复性的代码,那肯定会有程序员受不了,好家伙,后续在 vscode 里面真出了插件。

因为有一段时间没有使用了,大概记得是当你创建一个 jsx 文件时,输入 rfc 然后按回车就可以生成模版代码了,确实方便许多。

另外,对于 class 语法来说,有一点不自在的点就是 this 这玩意了,经常性要给函数绑定 this,绑来绑去对于我这种新手菜鸡而言 this 一下搞混了,到底谁指了谁?

到大四了,我选择没有学习 React 了,这个学习成本会比 Vue 大一点,当时也没有很长时间给我准备框架底层原理这些,因此当时是以 Vue 为核心进行深度学习,学习底层的一些原理方法。

到后来,因为目前公司技术栈所需,我又重回学习 React 了,没想到版本号就到了 16.8 了,这是一个引起社区重大改动的版本,我开始学习了起来,先找博客,然后看视频,最后再学习官方文档,不能说是掌握很扎实,至少也是学的很有兴趣,自己也做了一些小 demo,现在上手公司项目也不成大问题。

一句话总结:hook 实在是太香了!

接下来,我们主要介绍一下两个 Hook,一个是 useState,另外一个是 useEffect,其它的 Hook 暂时不介绍哈,目前的项目版本还不是很需要。感兴趣的同学们可以自行查阅 React 官方中文文档 学习。

在这里说明一下原因吧,开篇也说明过减少一些学习成本,useState 和 useEffect 是非常常用的两个 Hook,这也是为什么就连官方文档都会将它们排在前面。

使用 useState

官方文档:基础 Hook-useState

基础知识

以下是它的基础语法:

const [state, setState] = useState(initialState);

大家最好是结合官方文档来看。对于这个语法来说的话,又让我联想到 Java 了(毕竟大学里学的就是 Java ,代码也是写的最多),这个语法就好比 getter 和 setter,state 就是我们可以用的值,而 setState 就是设置值, React 官方对于变量命名也是比较规范直观的。

代码示例

下面用官方文档提供的例子来改造一下我们的 App.jsx 文件,代码如下:

import React, { useState } from 'react'

function App() {
  const [count, setCount] = useState(0);
  return (
    <>
      Count: {count}
      <button onClick={() => setCount(0)}>Reset</button>
      <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
      <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
    </>
  );
}

export default App

大体界面如下图所示,比较简单,一个显示结果的区域,三个按钮。

“+” 和 “-” 按钮采用函数式形式,因为被更新的 state 需要基于之前的 state。但是“重置”按钮则采用普通形式,因为它总是把 count 设置回初始值。

我们项目当中目前使用来说就如上述代码所示,不会涉及一些「高端操作」,如果已经学会使用的小伙伴可以跳到下一节了。还没有看懂的小伙伴可以把代码自己动手敲一遍,看看实际效果。

使用 useEffect

官方文档:基础 Hook-useEffect

基础知识

以下是它的基础语法:

useEffect(() => {
  const subscription = props.source.subscribe();
  return () => {
    // 清除订阅
    subscription.unsubscribe();
  };
},[]);

大家最好是结合官方文档来看。对于 useEffect,也是比较重要的 Hook,当初学习 class 语法的时候,componentDidMount 和 componentWillUnmount 这一长串的文字对我这种刚接触 React 的同学来说一下带来了入门到放弃的感觉。

而现在有了 useEffect 来说,不论是编码还是书写规范都顺畅了许多,过去可能写的时候都不知道哪些代码应该写在哪个生命周期函数里面,还要查资料,甚至有时候写错位置了,还在疑惑:诶,这数据怎么没出来,诶,怎么这里是这样的…

虽然说过去 componentDidMount 和 componentWillUnmount 这一长串的文字对于英文水平不是很好的同学刚开始会有一点压力,但是熟悉之后,你会发现这么命名也是一种比较好理解的方式,直接看英文名就知道这个生命周期函数的使用了。

注:useEffect 在 React 的渲染过程中是被异步调用的

注意事项

官方文档:基础 Hook-useEffect 中,还是提及了许多的注意事项。

默认情况下,effect 会在每轮组件渲染完成后执行。这样的话,一旦 effect 的依赖发生变化,它就会被重新创建。

文字理解可能会有点吃力,我们用实际代码来展示一下,继续往下看吧。

代码示例

下面我们继续用上一节的代码来改造一下我们的 App.jsx 文件,代码如下:

import React, { useState, useEffect } from 'react'

function App() {
  const [count, setCount] = useState(0);
  
  useEffect(()=>{
    console.log('Hello React 17 + Vite App!')
  }, [])

  return (
    <>
      Count: {count}
      <button onClick={() => setCount(0)}>Reset</button>
      <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
      <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
    </>
  );
}

export default App

此时,在控制台会打印出 Hello React 17 + Vite App!

这个就类似于 class 语法中的 componentDidMount 生命周期,细心的同学们可能已经发现了,我在 useEffect 中传递了第二个参数,但是是一个空数组,这个是我们下文要讲到的,这是 effect 所依赖的值数组。

我们有时候并不需要在每次组件更新时都创建新的订阅,而是仅需要在某一些变量改变时重新创建。此时可以给 useEffect 传递第二个参数,它是 effect 所依赖的值数组(多个变量通过英文逗号分隔)。

代码示例

在这里,得有一个注意事项,确保数组中包含了所有外部作用域中会发生变化且在 effect 中使用的变量,否则你的代码会引用到先前渲染中的旧变量。

因此,当我们需要依赖于某个变量时,我们不仅要给 useEffect 传递第二个参数,还要在 effect 中使用变量,具体可以参考如下代码:

import React, { useState, useEffect } from 'react'

function App() {
  const [count, setCount] = useState(0);
  
  useEffect(()=>{
    console.log('Hello React 17 + Vite App!', count)
  }, [count])

  return (
    <>
      Count: {count}
      <button onClick={() => setCount(0)}>Reset</button>
      <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
      <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
    </>
  );
}

export default App

当我们点击按钮 + 号 5 次时,控制台打印 5 条信息,诶,这下面不是有 6 条信息嘛,那是因为初次渲染时还是会执行,所以初次执行时 count 还是为初始值 0,所以会打印第一条信息。

感谢 & 期待下一篇

项目介绍本篇就到此结束了,让我们期待接下来的文章吧。

博主 21 届本科毕业,可以称呼我 Chocolate,喜欢可以关注一下。

现在关注以后就是老粉了,希望小伙伴们能够喜欢我的文章,这里是小狮子前端,保持狮子座的热情带给你学习的动力,愿我们成为最好的自己~

好文不白嫖哈,「点赞+评论+关注」就是给我最大更新的动力啦~

学如逆水行舟,不进则退

以上是关于React Hooks 入门基础(详细使用)的主要内容,如果未能解决你的问题,请参考以下文章

入门React 17 + Vite + ECharts 实现疫情数据可视化「03 学习 React Hooks」

React Hooks: Lazy Loading Breaks useLayoutEffect?

第六篇:React-Hooks 设计动机与工作模式(上)

React Hooks 快速入门:从一个数据请求开始

使用react-router+hooks搭建基础框架

PyTorch基础(17)-- hooks机制※