当前位置: 首页 > 知识库问答 >
问题:

javascript - React:如何使用useCallback以避免全量更新?

毛缪文
2024-01-20

react 如何使用useCallback 避免全量更新?

在子组件的事件中使用useCallback

fd3e60779771043277351a5329d1868.png

父组件 list.map 创建了子组件, 子组件触发事件导致 父组件的 list 发生变更, 于是组件全部发生了变化
这个过程中只有其中一个子组件发生了改变,所以我使用了 memo 包裹了一下
但是 传递的事件函数会重复创建,导致子组件全量更新
我应该如何使用useCallback 来实现顶点更新?

<SingleCircle    fill="#fff" name={name} x={x} y={y} radius={4 / scale}    onDragEnd={() => onDrop(name)}    onDragMove={(e: TKDragEvent) => onDragMove(e, index)}    onMouseOver={() => dispatch(setSelectPointKey(name))}    // 注释这样写会报错    // onDragEnd={useCallback(() => onDrop(name), [])}    // onDragMove={useCallback((e: TKDragEvent) => onDragMove(e, index), [index])}    // onMouseOver={useCallback(() => dispatch(setSelectPointKey(name)), [])}/>

image.png
image.png

共有2个答案

卜凯旋
2024-01-20

useCallback 提到外面去就好了,报错是因为这样写在 map 循环里面
image.png
image.png

当然还可以使用其他方案

  • 比如 ahooks 里面的 useMemoizedFn,是之前 React 官方 useEvent 提案的实现,函数引用始终不会变,并且不会产生过期闭包,无需依赖项
    https://ahooks.js.org/zh-CN/hooks/use-memoized-fn
墨承泽
2024-01-20

要使用 useCallback 来避免不必要的重新渲染,你需要确保回调函数在每次渲染时都保持不变。在你的例子中,你可以使用 useCallback 来创建这些回调函数,并将它们作为 onDragEndonDragMoveonMouseOver 的属性。

首先,你需要创建一个状态变量来存储 onDroponDragMovesetSelectPointKey 函数的引用。然后,在函数体内部,使用 useCallback 钩子来创建一个回调函数,并将其存储在相应的状态变量中。

下面是一个示例代码:

import React, { useState, useCallback } from 'react';function ParentComponent() {  const [list, setList] = useState([/* 初始列表 */]);  const [selectedPointKey, setSelectedPointKey] = useState(null);  const onDrop = (name) => {    // 处理 onDrop 逻辑  };  const onDragMove = (e, index) => {    // 处理 onDragMove 逻辑  };  const setSelectPointKey = (name) => {    // 处理 setSelectPointKey 逻辑  };  const onDragEndCallback = useCallback(() => onDrop, []); // 创建 onDrop 回调函数  const onDragMoveCallback = useCallback((e, index) => onDragMove(e, index), [index]); // 创建 onDragMove 回调函数,并依赖 index 防止重新渲染  const setSelectPointKeyCallback = useCallback(() => setSelectPointKey, []); // 创建 setSelectPointKey 回调函数  return (    <div>      {list.map((item, index) => (        <SingleCircle          fill="#fff"          name={item.name}          x={item.x}          y={item.y}          radius={4 / item.scale}          onDragEnd={onDragEndCallback} // 使用创建的回调函数作为 onDragEnd 属性          onDragMove={(e: TKDragEvent) => onDragMoveCallback(e, index)} // 使用创建的回调函数作为 onDragMove 属性,并传递 index 作为参数          onMouseOver={() => setSelectedPointKey(item.name)} // 根据你的需求修改 onMouseOver 处理函数        />      ))}    </div>  );}

这样,只有当 index 值改变时,onDragMove 的回调函数才会改变,从而触发组件的重新渲染。其他情况下,回调函数保持不变,因此不会触发不必要的重新渲染。

 类似资料:
  • 问题内容: 我们都知道全局变量只是最佳实践。但是在有些情况下,没有它们很难编写代码。您使用什么技术来避免使用全局变量? 例如,在以下情况下,您将如何不使用全局变量? JavaScript代码: 相关标记: 此代码来自具有多个的网络表单。它一次上传一个文件,以防止大量请求。它通过POST到iframe来完成此操作,等待响应触发iframeonload,然后触发下一个提交。 您不必专门回答此示例,我只

  • 现在遇到一个项目,uniapp开发的微信小程序,之前的所有页面都没有使用scope将css样式私有化,导致css属性全局污染了,现在要开发后续的功能,如何在后续的开发中避免之前css的样式污染? 之前开发的内容不能使用scope将css私有化,因为一旦私有化可能会对某些页面造成影响,现在的情况就是之前的内容不能动,在此基础上开发。 目前想到的办法是在后续开发的功能中,所有的css类名名全部使用当前

  • 我最近开始将样式化组件与React一起使用,我不确定我是否正确地处理了一个不断重复出现的特定情况。 假设我有一个非常简单的组件,比如,它只需要非常多的样式和一些给定的内容。我现在要处理的事情如下: 我发现首先定义基本组件,如,只针对样式,然后再定义另一个组件,它接受道具并使用该样式组件。 有没有更短的方法只在一个组件中完成这两个任务?我希望能有一些像... ...但那似乎不起作用。

  • 我一直在思考jvm安全的工作方式。原则是,jvm始终信任并运行任何本地代码。因此,从概念上讲,如果您的代码没有显式或隐式调用<code>checkpermission(permission)</code>,这意味着它永远不会失败任何安全验证。当然,所有这些验证调用通常都是在JavaAPI类中完成的,因此我们不需要为内置权限调用它们。 现在,只要您使用内置类(如<code>FileOutputStr

  • 我有一个带有jsonb列的PostgreSQL表,其中包含一个字符串数组,这些字符串是标记值,如下所示:。我有一个自定义绑定,用于将JSON与jackson JSONode进行转换。 自定义绑定定义如下:https://gist.github.com/helgeg/0C0B14228F75E91B7542BD6979A05B49 用基本的find读取记录,然后我提取JSON列,如下所示: 这是使用

  • Facebook React鼓励您将可变()和不可变()状态分开: 尽量让您的组件尽可能多的无状态。通过这样做,您可以将状态隔离到最符合逻辑的位置,并最大限度地减少冗余,从而更容易对应用程序进行推理。 当状态改变时,您应该调用来触发虚拟DOM diff,只有在需要时才会导致真正的DOM更新。 有一种方法可以通过调用手动触发DOM更新,但不鼓励: 通常情况下,您应该尽量避免使用,并且只从和中的读取。