usecallback()與usememo()

簡單的說

都是用來監聽數據變化 來進行控制渲染、減少不必要的渲染 、優化性能
usecallback()是用來監聽數據變化從而調用方法
usememo()是用來監聽數據變化從而改變數據 使用return返回變化的數據 當然return 也可以返回方法 所以usememo()可以代替usecallback()

下面詳解

useCallback:緩存回調函數

在 React 函數組件中,每一次 UI 的變化,都是通過重新執行整個函數來完成的,這和傳統的 Class 組件有很大區別:函數組件中并沒有一個直接的方式在多次渲染之間維持一個狀態。 比如下面的代碼中,我們在加號按鈕上定義了一個事件處理函數,用來讓計數器加 1。但是因為定義是在函數組件內部,因此在多次渲染之間,是無法重用 handleIncrement 這個函數的,而是每次都需要創建一個新的:

function Counter() {const [count, setCount] = useState(0);const handleIncrement = () => setCount(count + 1);// ...return <button onClick={handleIncrement}>+</button>
}

你不妨思考下這個過程。每次組件狀態發生變化的時候,函數組件實際上都會重新執行一遍。在每次執行的時候,實際上都會創建一個新的事件處理函數 handleIncrement。
這個事件處理函數中呢,包含了 count 這個變量的閉包,以確保每次能夠得到正確的結果。 這也意味著,即使 count 沒有發生變化,但是函數組件因為其它狀態發生變化而重新渲染時,這種寫法也會每次創建一個新的函數
創建一個新的事件處理函數,雖然不影響結果的正確性,但其實是沒必要的。因為這樣做不僅增加了系統的開銷,更重要的是:每次創建新函數的方式會讓接收事件處理函數的組件,需要重新渲染。
比如這個例子中的 button 組件,接收了 handleIncrement ,并作為一個屬性。如果每次都是一個新的,那么這個 React 就會認為這個組件的 props 發生了變化,從而必須重新渲染。因此,我們需要做到的是:**只有當 count 發生變化時,我們才需要重新定一個回調函數。**而這正是 useCallback 這個 Hook 的作用。

import React, { useState, useCallback } from 'react';
function Counter() {const [count, setCount] = useState(0);const handleIncrement = useCallback(() => setCount(count + 1),[count], // 只有當 count 發生變化時,才會重新創建回調函數);// ...return <button onClick={handleIncrement}>+</button>
}

在這里,我們把 count 這個 state ,作為一個依賴傳遞給 useCallback。這樣,只有 count 發生變化的時候,才需要重新創建一個回調函數,這樣就保證了組件不會創建重復的回調函數。而接收這個回調函數作為屬性的組件,也不會頻繁地需要重新渲染。

useMemo:緩存計算的結果

如果某個數據是通過其它數據計算得到的,那么只有當用到的數據,也就是依賴的數據發生變化的時候,才應該需要重新計算。
舉個例子,對于一個顯示用戶信息的列表,現在需要對用戶名進行搜索,且 UI 上需要根據搜索關鍵字顯示過濾后的用戶,那么這樣一個功能需要有兩個狀態:
1.用戶列表數據本身:來自某個請求。
2.搜索關鍵字:用戶在搜索框輸入的數據。
無論是兩個數據中的哪一個發生變化,都需要過濾用戶列表以獲得需要展示的數據。那么如果不使用 useMemo 的話,就需要用這樣的代碼實現:

import React, { useState, useEffect } from "react";export default function SearchUserList() {const [users, setUsers] = useState(null);const [searchKey, setSearchKey] = useState("");useEffect(() => {const doFetch = async () => {// 組件首次加載時發請求獲取用戶數據const res = await fetch("https://reqres.in/api/users/");setUsers(await res.json());};doFetch();}, []);let usersToShow = null;if (users) {// 無論組件為何刷新,這里一定會對數組做一次過濾的操作usersToShow = users.data.filter((user) =>user.first_name.includes(searchKey),);}return (<div><inputtype="text"value={searchKey}onChange={(evt) => setSearchKey(evt.target.value)}/><ul>{usersToShow &&usersToShow.length > 0 &&usersToShow.map((user) => {return <li key={user.id}>{user.first_name}</li>;})}</ul></div>);
}

在這個例子中,無論組件為何要進行一次重新渲染,實際上都需要進行一次過濾的操作。但其實你只需要在 users 或者 searchKey 這兩個狀態中的某一個發生變化時,重新計算獲得需要展示的數據就行了。那么,這個時候,我們就可以用 useMemo 這個 Hook 來實現這個邏輯,緩存計算的結果
//…
// 使用 userMemo 緩存計算的結果

const usersToShow = useMemo(() => {if (!users) return null;return users.data.filter((user) => {return user.first_name.includes(searchKey));}}, [users, searchKey]);
//...

可以看到,通過 useMemo 這個 Hook,可以避免在用到的數據沒發生變化時進行的重復計算。雖然例子展示的是一個很簡單的場景,但如果是一個復雜的計算,那么對于提升性能會有很大的幫助。
這也是 userMemo 的一大好處:避免重復計算。 除了避免重復計算之外,useMemo 還有一個很重要的好處:避免子組件的重復渲染。比如在例子中的 usersToShow 這個變量,如果每次都需要重新計算來得到,那么對于 UserList 這個組件而言,就會每次都需要刷新,因為它將 usersToShow 作為了一個屬性。而一旦能夠緩存上次的結果,就和 useCallback 的場景一樣,可以避免很多不必要的組件刷新。

這個時候,如果我們結合 useMemo 和 useCallback 這兩個 Hooks 一起看,會發現一個有趣的特性,那就是 useCallback 的功能其實是可以用 useMemo 來實現的。比如下面的代碼就是利用 useMemo 實現了 useCallback 的功能

 const myEventHandler = useMemo(() => {// 返回一個函數作為緩存結果return () => {// 在這里進行事件處理}}, [dep1, dep2]);

理解了這一點,相信你一下子會對這兩個 Hooks 的機制有更進一步的認識,也就不用死記硬背兩個 API 都是干嘛的了,因為從本質上來說,它們只是做了同一件事情:建立了一個綁定某個結果到依賴數據的關系。只有當依賴變了,這個結果才需要被重新得到。

深入討論usecallback()

開發過程中我遇到了

const toggleTheme = useCallback(() => 
{ 
setTheme((theme) =>(theme === "light" ? "dark" : "light")); 
}, []);

疑問?為什么沒有依賴項 不需要依賴theme 獲取最新的theme的值么
答:
useCallback 的依賴項數組是用于確定何時重新計算緩存的函數的。如果依賴項數組中有任何值發生變化,那么函數將被重新創建。

然而,對于 toggleTheme 函數,你并不需要在依賴項數組中包含 theme。這是因為你是在函數內部直接讀取 theme 的最新值,而不是依賴于外部的 theme 變量。這是 setTheme 函數的一個特性:當你傳遞一個函數給 setTheme,React 會將 當前的 theme 狀態值作為那個函數的參數

所以,即使 theme 值在多次渲染之間發生變化,toggleTheme 函數總是能讀取到最新的 theme 值,因此不需要在依賴項數組中包含 theme。

這種模式在你想要根據當前狀態值更新狀態時是非常有用的,因為它可以確保你總是使用最新的狀態值,而不是在閉包中緩存的舊值。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/40396.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/40396.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/40396.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

常見的編碼技術簡介

常見的編碼技術簡介 文章目錄 常見的編碼技術簡介1. 字符編碼1.1 ASCII1.2 Unicode 2. 數據傳輸編碼2.1 Base系列編碼2.1.1 Base642.1.2 Base162.1.3 Base322.1.4 Base852.1.5 其他Base編碼 2.2 URL編碼2.3 JSON2.4 XML2.5 Protobuf (Protocol Buffers) 1. 字符編碼 1.1 ASCII…

AI是在幫助開發者還是取代他們?——探討AI在軟件開發中的角色與未來

引言 隨著人工智能技術的迅猛發展&#xff0c;AI工具在軟件開發中的應用越來越廣泛。有人認為AI可以顯著提升開發者的效率&#xff0c;而也有人擔心AI會取代開發者的工作。本文將從三個方面探討AI在軟件開發中的角色&#xff1a;AI工具現狀、AI對開發者的影響以及AI開發的未來…

學習springAOP

第三章 Spring AOP 第一節 AOP 簡介 1. 概念 AOP全稱為Aspect Oriented Programming&#xff0c;表示面向切面編程。何為切面呢&#xff1f; 由此可以得出&#xff0c;切面是一種將那些與業務無關&#xff0c;但業務模塊都需要使用的功能封裝起來的技術。這樣便于減少系統的…

昇思25天學習打卡營第4天|應用實踐

昇思25天學習打卡營第4天 文章目錄 昇思25天學習打卡營第4天基于 MindSpore 實現 BERT 對話情緒識別模型簡介環境配置數據集數據加載和數據預處理input_idsattention_mask 模型構建模型驗證模型推理自定義推理數據集 打卡記錄 基于 MindSpore 實現 BERT 對話情緒識別 模型簡介…

奧比中光astra_pro相機使用記錄

一、信息獲取 1、官網 用于了解產品信息 http://www.orbbec.com.cn/sys/37.html 2、開發者社區 咨詢問題下載開發部https://developer.orbbec.com.cn/ 二 、windowvs19 1、相機型號 orbbec_astro_pro 根據對應的型號找到需要的包工具 踩坑1&#xff0c;因為這個相機型號…

第20章 Mac+VSCode配置C++環境

1. 下載VSCode VSCode下載地址在mac終端里輸入xcode- select --install命令&#xff0c;根據提示安裝xcode工具。 2. 安裝插件&#xff08;4個&#xff09; 打開VScode&#xff0c;點擊應用右側菜單欄 C/C&#xff08;必裝&#xff09; Code Runner&#xff08;必裝&#xf…

UCOS-III 任務調度與就緒列表管理

01. 就緒優先級位圖 在實時操作系統中&#xff0c;任務調度的效率至關重要。UCOS-III通過就緒優先級位圖來快速查找最高優先級的就緒任務&#xff0c;從而實現高效調度。就緒優先級位圖是一個按位表示的結構&#xff0c;每個位代表一個優先級&#xff0c;當某個優先級上有任務就…

高效管理 TensorFlow 2 GPU 顯存的實用指南

前言 在使用 TensorFlow 2 進行訓練或預測時&#xff0c;合理管理 GPU 顯存至關重要。未能有效管理和釋放 GPU 顯存可能導致顯存泄漏&#xff0c;進而影響后續的計算任務。在這篇文章中&#xff0c;我們將探討幾種方法來有效釋放 GPU 顯存&#xff0c;包括常規方法和強制終止任…

【FFmpeg】avcodec_open2函數

目錄 1. avcodec_open21.1 編解碼器的預初始化&#xff08;ff_encode_preinit & ff_decode_preinit&#xff09;1.2 編解碼器的初始化&#xff08;init&#xff09;1.3 釋放編解碼器&#xff08;ff_codec_close&#xff09; FFmpeg相關記錄&#xff1a; 示例工程&#xff…

Windows編程之多線程事件對象(Event Object)用法詳解

目錄 一、前言 二、基礎用法 三、API詳解 1.創建事件對象 2控制事件狀態 3.等待事件對象&#xff1a; 四、實戰案例 1.案例描述 2.代碼設計 3.總設計代碼 4.運行結果 一、前言 事件對象&#xff08;Event Object&#xff09;是我們在大型項目中&#xff0c;進行多線…

競賽選題 醫學大數據分析 - 心血管疾病分析

文章目錄 1 前言1 課題背景2 數據處理3 數據可視化4 最后 1 前言 &#x1f525; 優質競賽項目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于大數據的心血管疾病分析 該項目較為新穎&#xff0c;適合作為競賽課題方向&#xff0c;學長非常推薦&#xff01; &#x1f9…

AI繪畫Stable Diffusion 解鎖精美壁紙創作:利用SD與LLM定制你的專屬壁紙,AI副業變現指南!

大家好&#xff0c;我是畫畫的小強 今天給大家分享一下用AI繪畫Stable Diffusion 制作精美手機壁紙&#xff0c;這也可能是當前最快AIGC變現的一種途徑。雖然本文的主題為手機壁紙&#xff0c;當調整不同的比例的分辨率寬高比例&#xff0c;就可以直接復用到手機、電腦和平板、…

旋轉和鏡像的關系

旋轉矩陣行列式與 在E(3)三維空間中&#xff0c;旋轉矩陣的行列式可以用來判斷該旋轉是否包含鏡像變換。 行列式為正&#xff1a; 表示純旋轉&#xff0c;不包含鏡像。 旋轉矩陣保持向量的長度和角度不變&#xff0c;只是改變向量的方向。 行列式為負&#xff1a; 表示旋轉…

機器學習原理之 -- 支持向量機分類:由來及原理詳解

支持向量機&#xff08;Support Vector Machine, SVM&#xff09;是統計學習理論的一個重要成果&#xff0c;廣泛應用于分類和回歸問題。SVM以其高效的分類性能和良好的泛化能力在機器學習領域中占據重要地位。本文將詳細介紹支持向量機的由來、基本原理、構建過程及其優缺點。…

LVS負載均衡群集部署之——DR模式的介紹及搭建步驟

一、LVS-DR集群介紹1.1 LVS-DR 工作原理1.2 數據包流向分析1.3 LVS-DR 模式的特點1.4 LVS-DR中的ARP問題1.4.1 問題一1.4.2 問題二二、構建LVS-DR集群2.1 構建LVS-DR集群的步驟&#xff08;理論&#xff09;1.配置負載調度器&#xff08;192.168.80.30&#xff09;&#xff08;…

5分鐘教你用AI把老照片動起來,別再去花49塊9的冤枉錢了

文章目錄 需要的工具 最近&#xff0c;AI視頻在各大平臺上&#xff0c;又火了。 只是火的形式&#xff0c;變成了將老照片動起來&#xff0c;打情感牌&#xff0c;或者做很多經典電視劇的再整活。 直接把可靈的生成時間&#xff0c;從以前的4分鐘&#xff0c;生生的干成了20分鐘…

鴻蒙應用筆記

安裝就跳過了&#xff0c;一直點點就可以了 配置跳過&#xff0c;就自動下了點東西。 鴻蒙那個下載要12g個內存&#xff0c;大的有點嚇人。 里面跟idea沒區別 模擬器或者真機運行 真機要鴻蒙4.0&#xff0c;就可以實機調試 直接在手機里面跑&#xff0c;這個牛逼&#xf…

國標GB/T 28181詳解:國標GBT28181-2022 SIP服務器發起廣播的命令流程

目錄 一、定義 二、作用 1、實現信息的集中管理和分發 &#xff08;1&#xff09;信息集中 &#xff08;2&#xff09;信息分發 2、提高信息傳輸的可靠性和效率 &#xff08;1&#xff09;可靠性 &#xff08;2&#xff09;提高效率 3、支持多種設備和系統的互通 &am…

mongdb學習與使用

1. 基礎概念 MongoDB簡介&#xff1a; MongoDB是一個基于文檔的NoSQL數據庫&#xff0c;具有高性能、高可用性和易擴展性。數據存儲在類似JSON的BSON格式中。 基本術語&#xff1a; Database&#xff08;數據庫&#xff09;&#xff1a; 集合的容器。Collection&#xff08;集合…

國產強大免費WAF, 社區版雷池動態防護介紹

雷池WAF&#xff0c;基于智能語義分析的下一代 Web 應用防火墻 使用情況 我司于2023年4月23日對雷池進行測試&#xff0c;測試一個月后&#xff0c;于2023年5月24日對雷池進行正式切換&#xff0c;此時版本為1.5.1。 里程碑紀念 后續一直跟隨雷池進行版本升級&#xff0c;當前…