首頁 > web前端 > js教程 > 主體

一文帶你深入了解React Hooks!

青灯夜游
發布: 2022-03-21 11:31:55
轉載
2327 人瀏覽過

React中你了解Hooks嗎?這篇文章帶大家來深入了解下React Hooks,希望對大家有幫助!

一文帶你深入了解React Hooks!

前言

Hooks 用於不寫 class 的情況下,使用 state 以及其他 React 特性。那麼 Hooks 究竟是什麼,為什麼要使用 Hooks,React 提供了哪些常用 Hooks,以及如何自訂 Hooks 呢,下文將為您一一揭曉。 【相關推薦:Redis影片教學

什麼是 Hooks

Hooks 譯為鉤子,Hooks 就是在函數元件內,負責鉤進外部功能的函數。

React 提供了一些常用鉤子,React 也支援自訂鉤子,這些鉤子都是用來為函數引入外部功能。

當我們在元件中,需要引入外部功能時,就可以使用 React 提供的鉤子,或自訂鉤子。

例如在元件內引入可管理 state 的功能,就可以使用 useState 函數,下文會詳細介紹 useState 的用法。

為什麼要用 Hooks

使用 Hooks 有 2 大原因:

  • 簡化邏輯重複使用;
  • 讓複雜元件更容易理解。

1. 簡化邏輯重複使用

在Hooks 出現之前,React 必須藉用高階元件、render props 等複雜的設計模式才能實現邏輯的復用,但是高階組件會產生冗餘的組件節點,讓偵錯更加複雜。

Hooks 讓我們可以在無需修改元件結構的情況下重複使用狀態邏輯,下文會詳細介紹自訂 Hooks 的用法。

2. 讓複雜元件更容易理解

在class 元件中,同一個業務邏輯的程式碼分散在元件的不同生命週期函數中,而Hooks 能夠讓同一個業務邏輯的程式碼聚合在一塊,讓業務邏輯清楚地隔離開,讓程式碼更容易理解和維護。

四、常用的 Hooks

1. useState

useState 是允許你在 React 函式元件中新增 state 的 Hook。

使用範例如下:

import React, { useState } from 'react';

function Example() {
  // 声明一个叫 "count" 的 state 变量
  const [count, setCount] = useState(0);
  // ...
登入後複製

以上程式碼宣告了初始值為 0 的 state 變數 count,透過呼叫 setCount 來更新目前的 count。

2. useEffect

useEffect 可以讓你在函數元件中執行副作用操作。

副作用是指一段和目前執行結果無關的程式碼,常用的副作用操作如資料取得、設定訂閱、手動變更 React 元件中的 DOM。

useEffect 可以接收兩個參數,程式碼如下:

useEffect(callback, dependencies)
登入後複製

第一個參數是要執行的函數 callback,第二個參數是可選的相依性陣列 dependencies。

其中依賴項是可選的,如果不指定,那麼callback 就會在每次函數元件執行完後都執行;如果指定了,那麼只有依賴項中的值發生變化的時候,它才會執行。

使用範例如下:

function Example() {
  const [count, setCount] = useState(0);

  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;

    return () => {
        // 可用于做清除,相当于 class 组件的 componentWillUnmount
    }

  }, [count]); // 指定依赖项为 count,在 count 更新时执行该副作用
  // ...
登入後複製

以上程式碼透過 useEffect 實作了當依賴項 count 更新時,執行副作用函數,並透過傳回回呼函數清除上一次的執行結果。

另外,useEffect 提供了四種執行副作用的時機:

  • #每次 render 後執行:不提供第二個相依性參數。例如 useEffect(() => {});
  • 僅第一次 render 後執行:提供一個空數組作為依賴項。例如 useEffect(() => {}, []);
  • 第一次以及相依性發生變更後執行:提供相依性陣列。例如 useEffect(() => {}, [deps]);
  • #元件 unmount 後執行:傳回一個回呼函數。如 useEffect() => { return () => {} }, [])。

3. useCallback

useCallback 定義的回呼函數只會在依賴項改變時重新宣告這個回呼函數,這樣就保證了元件不會建立重複的回調函數。而接收這個回呼函數作為屬性的元件,也不會頻繁地需要重新渲染

使用範例如下:

const memoizedCallback = useCallback(() => {
  doSomething(a, b)
}, [a, b])
登入後複製

以上程式碼在依賴 a、b 發生變化時,才會重新宣告回呼函數。

4. useMemo

useMemo 定義的建立函數只會在某個依賴項改變時才重新計算,有助於每次渲染時不會重複的高開銷的計算,而接收這個計算值作為屬性的元件,也不會頻繁地需要重新渲染

使用範例如下:

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b])
登入後複製

以上程式碼在依賴 a、b 發生變化時,才會重新計算。

5. useRef

useRef 傳回一個 ref 對象,這個 ref 物件在元件的整個生命週期內持續存在。

他有 2 個用處:

  • 保存 DOM 节点的引用
  • 在多次渲染之间共享数据

保存 DOM 节点的引入使用示例如下:

function TextInputWithFocusButton() {
  const inputEl = useRef(null)
  const onButtonClick = () => {
    // `current` 指向已挂载到 DOM 上的文本输入元素
    inputEl.current.focus()
  }
  return (
    <>
      <input ref={inputEl} type=&#39;text&#39; />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  )
}
登入後複製

以上代码通过 useRef 创建了 ref 对象,保存了 DOM 节点的引用,可以对 ref.current 做 DOM 操作。

在多次渲染之间共享数据示例如下:

import React, { useState, useCallback, useRef } from &#39;react&#39;

export default function Timer() {
  // 定义 time state 用于保存计时的累积时间
  const [time, setTime] = useState(0)

  // 定义 timer 这样一个容器用于在跨组件渲染之间保存一个变量
  const timer = useRef(null)

  // 开始计时的事件处理函数
  const handleStart = useCallback(() => {
    // 使用 current 属性设置 ref 的值
    timer.current = window.setInterval(() => {
      setTime((time) => time + 1)
    }, 100)
  }, [])

  // 暂停计时的事件处理函数
  const handlePause = useCallback(() => {
    // 使用 clearInterval 来停止计时
    window.clearInterval(timer.current)
    timer.current = null
  }, [])

  return (
    <div>
      {time / 10} seconds.
      <br />
      <button onClick={handleStart}>Start</button>
      <button onClick={handlePause}>Pause</button>
    </div>
  )
}
登入後複製

以上代码通过 useRef 创建了一个变量名为 timer 的 ref 对象,该对象可以在跨组件渲染时调用,在开始计时时新建计时器,在暂停计时时清空计时器。

6. useContext

useContext 用于接收一个 context 对象并返回该 context 的值,可以实现跨层级的数据共享。

示例如下:

// 创建一个 context 对象
const MyContext = React.createContext(initialValue)
function App() {
  return (
    // 通过 Context.Provider 传递 context 的值
    <MyContext.Provider value=&#39;1&#39;>
      <Container />
    </MyContext.Provider>
  )
}

function Container() {
  return <Test />
}

function Test() {
  // 获取 Context 的值
  const theme = useContext(MyContext) // 1
  return <div></div>
}
登入後複製

以上代码通过 useContext 取得了 App 组件中定义的 Context,做到了跨层次组件的数据共享。

7. useReducer

useReducer 用来引入 Reducer 功能。

示例如下:

const [state, dispatch] = useReducer(reducer, initialState)
登入後複製

它接受 Reducer 函数和状态的初始值作为参数,返回一个数组。数组的第一个成员是状态的当前值,第二个成员是发送 action 的 dispatch 函数。

五、自定义 Hooks

通过自定义 Hooks,可以将组件逻辑提取到可重用的函数中。

1. 如何创建自定义 Hooks?

自定义 Hooks 就是函数,它有 2 个特征区分于普通函数:

  • 名称以 “use” 开头;
  • 函数内部调用其他的 Hook。

示例如下:

import { useState, useCallback } from &#39;react&#39;

function useCounter() {
  // 定义 count 这个 state 用于保存当前数值
  const [count, setCount] = useState(0)
  // 实现加 1 的操作
  const increment = useCallback(() => setCount(count + 1), [count])
  // 实现减 1 的操作
  const decrement = useCallback(() => setCount(count - 1), [count])
  // 重置计数器
  const reset = useCallback(() => setCount(0), [])

  // 将业务逻辑的操作 export 出去供调用者使用
  return { count, increment, decrement, reset }
}

// 组件1
function MyComponent1() {
  const { count, increment, decrement, reset } = useCounter()
}

// 组件2
function MyComponent2() {
  const { count, increment, decrement, reset } = useCounter()
}
登入後複製

以上代码通过自定义 Hooks useCounter,轻松的在 MyComponent1 组件和 MyComponent2 组件之间复用业务逻辑。

2. 自定义 Hooks 库 - react-use

React 官方提供了 react-use 库,其中封装了大量可直接使用的自定义 Hooks,帮助我们简化组件内部逻辑,提高代码可读性、可维护性。

其中我们常用的自定义 Hooks 有:

  • useLocation 和 useSearchParam:跟踪页面导航栏位置状态;
  • useScroll:跟踪 HTML 元素的滚动位置;
  • useScrolling:跟踪 HTML 元素是否正在滚动;
  • useAsync, useAsyncFn, and useAsyncRetry:解析一个 async 函数;
  • useTitle:设置页面的标题。

可至 react-use 官网学习使用。

六、小结

本文从 Hooks 究竟是什么,为什么要使用 Hooks,React 提供了哪些常用 Hooks,以及如何自定义 Hooks 4 个方面介绍了 React Hooks,相信大家对 React Hooks 已经有了更加深入的理解。

希望能对你有所帮助,感谢阅读~

更多编程相关知识,请访问:编程入门!!

以上是一文帶你深入了解React Hooks!的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:juejin.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!