- ReactJS 教程
- ReactJS - 首页
- ReactJS - 简介
- ReactJS - 路线图
- ReactJS - 安装
- ReactJS - 特性
- ReactJS - 优点与缺点
- ReactJS - 架构
- ReactJS - 创建 React 应用
- ReactJS - JSX
- ReactJS - 组件
- ReactJS - 嵌套组件
- ReactJS - 使用新创建的组件
- ReactJS - 组件集合
- ReactJS - 样式
- ReactJS - 属性 (props)
- ReactJS - 使用属性创建组件
- ReactJS - props 验证
- ReactJS - 构造函数
- ReactJS - 组件生命周期
- ReactJS - 事件管理
- ReactJS - 创建一个事件感知组件
- ReactJS - 在 Expense Manager 应用中引入事件
- ReactJS - 状态管理
- ReactJS - 状态管理 API
- ReactJS - 无状态组件
- ReactJS - 使用 React Hooks 进行状态管理
- ReactJS - 使用 React Hooks 的组件生命周期
- ReactJS - 布局组件
- ReactJS - 分页
- ReactJS - Material UI
- ReactJS - Http 客户端编程
- ReactJS - 表单编程
- ReactJS - 受控组件
- ReactJS - 非受控组件
- ReactJS - Formik
- ReactJS - 条件渲染
- ReactJS - 列表
- ReactJS - Keys
- ReactJS - 路由
- ReactJS - Redux
- ReactJS - 动画
- ReactJS - Bootstrap
- ReactJS - Map
- ReactJS - 表格
- ReactJS - 使用 Flux 管理状态
- ReactJS - 测试
- ReactJS - CLI 命令
- ReactJS - 构建和部署
- ReactJS - 示例
- Hooks
- ReactJS - Hooks 简介
- ReactJS - 使用 useState
- ReactJS - 使用 useEffect
- ReactJS - 使用 useContext
- ReactJS - 使用 useRef
- ReactJS - 使用 useReducer
- ReactJS - 使用 useCallback
- ReactJS - 使用 useMemo
- ReactJS - 自定义 Hooks
- ReactJS 高级
- ReactJS - 可访问性
- ReactJS - 代码分割
- ReactJS - Context
- ReactJS - 错误边界
- ReactJS - 转发 Refs
- ReactJS - Fragments
- ReactJS - 高阶组件
- ReactJS - 与其他库集成
- ReactJS - 性能优化
- ReactJS - Profiler API
- ReactJS - Portals
- ReactJS - 无 ES6 ECMAScript 的 React
- ReactJS - 无 JSX 的 React
- ReactJS - Reconciliation
- ReactJS - Refs 和 DOM
- ReactJS - Render Props
- ReactJS - 静态类型检查
- ReactJS - Strict Mode
- ReactJS - Web Components
- 附加概念
- ReactJS - 日期选择器
- ReactJS - Helmet
- ReactJS - 内联样式
- ReactJS - PropTypes
- ReactJS - BrowserRouter
- ReactJS - DOM
- ReactJS - 走马灯
- ReactJS - 图标
- ReactJS - 表单组件
- ReactJS - 参考 API
- ReactJS 有用资源
- ReactJS - 快速指南
- ReactJS - 有用资源
- ReactJS - 讨论
ReactJS - useCallback
useCallback hook 类似于 useMemo hook,它提供记忆函数而非值的功能。由于回调函数是 JavaScript 编程中不可或缺的一部分,并且回调函数是通过引用传递的,因此 React 提供了一个单独的 hook,useCallback 来记忆回调函数。理论上,useMemo hook 本身可以实现 useCallback 的功能。但是,useCallback 提高了 React 代码的可读性。
useCallback hook 的签名
useCallback hook 的签名如下:
const <memoized_callback_fn> = useCallback(<callback_fn>, <dependency_array>);
这里,useCallback 接受两个输入并返回一个记忆的回调函数。输入参数如下:
callback_fn - 要记忆的回调函数。
dependency_array - 包含回调函数所依赖的变量。
useCallback hook 的输出是 callback_fn 的记忆回调函数。useCallback hook 的使用方法如下:
const memoizedCallbackFn = useCallback(() => { // code }, [a, b])
注意 - useCallback(callback_fn, dependency_array) 等效于 useMemo(() => callback_fn, dependency_array)。
应用 useCallback
让我们学习如何通过创建一个 React 应用来应用 useCallback hook。
首先,使用 create-react-app 命令创建一个并启动一个 React 应用,如下所示:
create-react-app myapp cd myapp npm start
接下来,在 components 文件夹下创建一个组件 PureListComponent (src/components/PureListComponent.js)
import React from "react"; function PureListComponent() { return <div>List</div> } export default PureListComponent
接下来,使用 PureListComponent 组件更新根组件,如下所示:
import PureListComponent from './components/PureListComponent'; function App() { return ( <div style={{ padding: "5px" }}> <PureListComponent /> </div> ); } export default App;
接下来,打开 PureListComponent.js 并添加两个 props
要在组件中显示的项目列表
用于在控制台中显示用户点击的项目的回调函数
import React from "react"; function PureListComponent(props) { const items = props['items']; const handleClick = props['handleClick'] console.log("I am inside the PureListComponent") return ( <div> {items.map((item, idx) => <span key={idx} onClick={handleClick}>{item} </span> )} </div> ) } export default React.memo(PureListComponent)
这里我们有:
使用 items props 获取项目列表
使用 handleClick 获取点击事件的处理程序
使用 React.memo 包装组件以记忆组件。由于组件将为给定的输入集渲染相同的输出,因此它在 React 中被称为 PureComponent。
接下来,让我们更新 App.js 并使用 PureListComponent,如下所示:
import React, {useState, useEffect} from 'react'; import PureListComponent from './components/PureListComponent'; function App() { // array of numbers var listOfNumbers = [...Array(100).keys()]; // callback function const handleCallbackFn = (e) => { console.log(e.target.innerText) } const [currentTime, setCurrentTime] = useState(new Date()) useEffect(() => { let interval = setInterval(() => { setCurrentTime(new Date()) }, 1000) return () => clearInterval(interval) }, [currentTime]) return ( <div style={ { padding: "5px" } }> <PureListComponent items={listOfNumbers} handleClick={handleCallbackFn}/> <div>Time: <b>{currentTime.toLocaleString().split(',')[1]}</b></div> </div> ); } export default App;
这里我们包含了一个状态 currentTime,并使用 setInterval 每秒更新它,以确保组件每秒重新渲染。
我们可能认为 PureListComponent 不会每秒重新渲染,因为它使用了 React.memo。但是,它会重新渲染,因为 props 值是引用类型。
接下来,更新根组件并使用 useMemo 和 useCallback 来保留数组和回调函数,如下所示:
import React, {useState, useEffect, useCallback, useMemo} from 'react'; import PureListComponent from './components/PureListComponent'; function App() { // array of numbers const listOfNumbers = useMemo(() => [...Array(100).keys()], []); // callback function const handleCallbackFn = useCallback((e) => console.log(e.target.innerText), []) const [currentTime, setCurrentTime] = useState(new Date()) useEffect(() => { let interval = setInterval(() => { setCurrentTime(new Date()) }, 1000) return () => clearInterval(interval) }, [currentTime]) return ( <div style={ { padding: "5px" } }> <PureListComponent items={listOfNumbers} handleClick={handleCallbackFn}/> <div>Time: <b>{currentTime.toLocaleString().split(',')[1]}</b></div> </div> ); } export default App;
这里我们有:
使用 useMemo 保留 items 数组
使用 useCallback 保留 handleClick 回调函数
最后,在浏览器中检查应用程序,它将不会每秒重新渲染 PureListComponent。
useCallback 的用例
useCallback hook 的一些用例如下:
具有函数 props 的纯函数组件
useEffect 或其他具有函数作为依赖项的 hooks
在去抖动/节流或类似操作期间使用函数
优点
useCallback hook 的优点如下:
易于使用的 API
易于理解
提高应用程序的性能
缺点
从技术上讲,useCallback 没有缺点。但是,在应用程序中过度使用 useCallback 会带来以下缺点。
降低应用程序的可读性
降低应用程序的可理解性
调试应用程序很复杂
开发人员应该深入了解 JavaScript 语言才能使用它
总结
useCallback 易于使用并提高性能。同时,useCallback 应该只在绝对必要时使用。它不应该在每种情况下都使用。一般规则是检查应用程序的性能。如果需要改进,那么我们可以检查使用 useCallback 是否有助于提高性能。如果我们得到肯定的回应,那么我们可以使用它。否则,我们可以将其留给 React 来改进和优化应用程序的性能。