網站首頁 編程語言 正文
簡介
如果你還不熟悉鉤子的概念,請務必查看本文章,因為它對鉤子的概念提供了一個非常好的、深入的概述,以及一些鉤子的例子。
useCallback
鉤子是用來緩存一個記憶化的回調函數,以節省任何重新計算的開銷。
這個鉤子可以阻止一個組件重新渲染,除非它的道具發生了變化,這意味著我們現在可以隔離資源密集型的函數,這樣它們就不會在每個組件渲染時自動運行。
最好是展示一個有利于使用該鉤子的場景,這樣我們就能更好地理解我們為達成一個問題所采取的步驟,然后再解釋使用useCallback
鉤子背后的思考過程。
項目概述
我們將從搭建一個全新的React項目的腳手架開始。首先,我們將創建一個新的項目目錄,之后,我們將使用終端初始化一個新項目。
在這個過程中,你可以使用npm、npx或者yarn。你要運行的命令是:
-
npm。
npm init react-app app-name
-
npx
: npx create-react-app app-name
-
yarn。
yarn create react-app app-name
現在我們已經設置好了一切,讓我們直接進入有趣的部分。
項目進展
由于這是一個小項目,我們將把所有的代碼放在根src
目錄下的App.js
文件內,它看起來會是這樣的:
import { useState, memo } from "react"; import './App.css'; const Todos = ({ todos, addTodo }) => { console.log("child render"); return ( <div className="todos-container"> <h2>My Todos</h2> <div className="todos"> {todos.map((todo, index) => { return <p key={index}>{todo}</p>; })} </div> <button onClick={addTodo}>Add Todo</button> </div> ); }; const MemoizedTodos = memo(Todos); const App = () => { const [count, setCount] = useState(0); const [todos, setTodos] = useState([]); const increment = () => { setCount((c) => c + 1); }; const addTodo = () => { setTodos((t) => [...t, "New Todo"]); }; return ( <div className="App"> <MemoizedTodos todos={todos} addTodo={addTodo} /> <hr /> <div className="counter-container"> <p>Count: {count}</p> <button onClick={increment}>+</button> </div> </div> ); }; export default App;
這里有相當多的東西需要解壓,所以讓我們看看我們有什么。
首先,我們定義了一個Todos
組件,它的道具是一個todos列表,以及一個函數,一旦被調用,就會添加一個新的todo。這個組件的任務是將todos渲染到屏幕上,并在按下Add Todo
按鈕時添加一個新的todo。
然后,我們有其余的App
組件,除了渲染和傳遞道具給MemoizedTodos
組件外,還在屏幕上顯示一個可以遞增的計數器。
而為了讓一切看起來更好一點,我們還將在我們的App.css
文件中添加以下樣式:
.App { text-align: left; width: 80vw; margin: 5vh auto 0 auto; }
那么,問題出在哪里?
現在,你可能會問自己:"這個應用程序有什么問題?";的確,一切似乎都在正常工作。然而,問題是,每次我們點擊+
按鈕來增加計數器時,Todos
組件就會被重新渲染。
我們可以通過檢查控制臺來檢查,每次我們重新渲染Todos
組件時,都會打印到控制臺。
意外的Todos
組件的重新渲染
問題的根本原因
你看,在App
組件中,我們定義了addTodo
函數,它將在每次App
組件重新渲染時被重新創建。當App
組件的狀態發生變化時,它就會重新渲染,其中包括todos和計數器。
我們正在使用[memo](https://reactjs.org/docs/react-api.html#reactmemo)
,所以Todos
組件不應該重新渲染,因為當計數增加時,todos
的狀態和addTodo
的功能都沒有改變。
因此,基本上,問題在于addTodo
是定義在App
組件內的,并且在該組件重新生成時被重新創建。
解決方法
實際上,我們有兩種方法可以解決這個問題:
- 通過在
App
組件之外定義addTodo
函數。 - 通過對
addTodo
函數的記憶化
雖然第一種方法似乎是明確的解決方案,但我們不能總是依靠將一個函數排除在組件的范圍之外,而使其成為一個純函數。
對函數進行記憶
然后我們再來看看useCallback
鉤子,它正是通過對函數進行備忘來解決我們現在面臨的這個問題,以避免其重構。
我們所要做的就是從React中導入useCallback
鉤子,并將調用鉤子的結果與鉤子的回調返回的狀態更新分配給addTodo
函數,就這樣:
const addTodo = useCallback(() => { setTodos((t) => [...t, "New Todo"]); }, []);
而這個輕微的調整應該可以解決我們之前的問題。
現在,如果你想知道為什么我們沒有把todos
數組添加到鉤子的依賴數組中,那是因為React會拾取狀態,因為我們使用的是以回調為參數的setTodos
函數,而不是一個數組值。
如果我們要改變這一點,我們應該看到一個警告。
setState的值而不是回調作為參數
useCallback依賴數組的警告
總結
我希望你喜歡讀這篇文章,并希望你對useCallback
鉤子是什么,它的作用,以及什么時候應該使用它有了更好的理解。
原文鏈接:https://juejin.cn/post/7176277831574356028
相關推薦
- 2022-02-27 Required String paramter ‘username‘ is not present
- 2024-03-02 前端directus對接單點登錄
- 2022-09-05 內置指令、自定義指令(詳細)、全局指令與局部指令
- 2022-07-15 Python?并行加速技巧分享_python
- 2021-12-11 關于docker容器部署redis步驟介紹_docker
- 2022-05-20 ElasticSearch 7.X系列之: 檢索性能優化實戰指南
- 2021-12-07 詳解C語言編程之thread多線程_C 語言
- 2022-11-26 React組件如何優雅地處理異步數據詳解_React
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支