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 Hooks 进行状态管理 ReactJS Hooks 的组件生命周期 ReactJS 布局组件 ReactJS 分页 ReactJS Material UI ReactJS Http 客户端编程 ReactJS 表单编程 ReactJS 受控组件 ReactJS 非受控组件 ReactJS Formik ReactJS 条件渲染 ReactJS 列表 ReactJS Key 键 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 上下文 ReactJS 错误边界 ReactJS 转发 Refs ReactJS 片段 ReactJS 高阶组件 ReactJS 与其他库集成 ReactJS 优化性能 ReactJS Profiler API ReactJS Portals ReactJS 不使用 ES6 ECMAScript ReactJS 不使用 JSX 的 React ReactJS Reconciliation ReactJS Refs 和 DOM ReactJS 渲染道具 ReactJS 静态类型检查 ReactJS 严格模式 ReactJS Web 组件

其他概念

ReactJS 日期选择器 ReactJS Helmet ReactJS 内联样式 ReactJS PropTypes ReactJS BrowserRouter ReactJS DOM ReactJS 轮播 ReactJS 图标 ReactJS 表单组件 ReactJS 参考 API

ReactJS 有用资源

ReactJS 快速指南 ReactJS 备忘录 Axios 备忘录 ReactJS 有用资源 ReactJS 讨论


ReactJS - useCallback

useCallback Hooks(钩子)类似于 useMemo Hooks(钩子),提供记忆函数而不是值的功能。由于回调函数是 JavaScript 编程不可或缺的一部分,并且回调函数是通过引用传递的,因此 React 提供了一个单独的Hooks(钩子) useCallback 来记忆回调函数。理论上,useCallback 功能可以使用 useMemo Hooks(钩子)本身来实现。但是,useCallback 提高了 React 代码的可读性。

useCallback Hooks(钩子)的签名

useCallback Hooks(钩子)的签名如下 −

const <memoized_callback_fn> = useCallback(<callback_fn>, <dependency_array>);

此处,useCallback 接受两个输入并返回一个记忆化回调函数。输入参数如下 −

  • callback_fn − 要记忆的回调函数。

  • dependency_array − 保存回调函数所依赖的变量。

useCallback Hooks(钩子)的输出是 callback_fn 的记忆化回调函数。useCallback Hooks(钩子)的用法如下 −

const memoizedCallbackFn = useCallback(() => {
   // code
}, [a, b])

注意 − useCallback(callback_fn, dependency_array) 相当于 useMemo(() => callback_fn, dependency_array)。

应用 useCallback

让我们通过创建一个 React 应用程序来学习如何应用 useCallback Hooks(钩子)。

首先,使用 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() {
   
   // 数字数组
   var listOfNumbers = [...Array(100).keys()];
   
   // 回调函数
   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() {
   
   // 数字数组
   const listOfNumbers = useMemo(() => [...Array(100).keys()], []);
   
   // 回调函数
   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 Hook 的签名

useCallback 的用例

useCallback Hooks(钩子)的一些用例如下 −

  • 带有函数的纯函数组件props

  • useEffect 或其他具有函数依赖项的Hooks(钩子)

  • 在防抖动/节流或类似操作期间使用函数

优点

useCallback Hooks(钩子)的优点如下 −

  • 易于使用的 API

  • 易于理解

  • 提高应用程序的性能

缺点

从技术上讲,useCallback 没有缺点。但是,在应用程序中大量使用 useCallback 会带来以下缺点。

  • 降低应用程序的可读性

  • 降低应用程序的可理解性

  • 应用程序调试很复杂

  • 开发人员应该对 JavaScript 语言有深入的了解才能使用它

总结

useCallback 易于使用并可提高性能。同时,useCallback 应仅在绝对必要时使用。它不应该在每个场景中都使用。一般规则是检查应用程序的性能。如果需要改进,那么我们可以检查 useCallback 的使用是否有助于提高性能。如果我们得到积极的回应,那么我们可以使用它。否则,我们可以把改进和优化应用程序性能的工作交给 React。