在Reaction中,当组件重新呈现时,将重新创建该组件内的所有函数,从而导致函数引用的更改.

这样,即使子组件被包装在Memo()中,也可以防止父组件导致不安全的重新渲染.如果从父组件将函数作为props 传递给它,它仍然会重新呈现吗?

下面是一个例子:

const Parent = () => { 
  const [state, setState] = useState("1"); 
 
  const handleIncrement = useCallback(() => { 
    const increment = setState(state + 1);  
  }, [state]);
 
  return (  
    <Child handle={() => handleIncrement()} /> 
  );
}

const Child = memo(({handle}) => {
  return();
});

这就是在传递给子组件的函数上使用useCallback()的主要目的吗?这样,函数的引用在不影响父组件中该函数的usecallback依赖数组的重新呈现之间保持不变.它通过子组件完成的引用相等性判断?

在将函数作为props 传递给子组件时,是否会导致保持相同的函数引用?防止重现者使Memo()的使用无效?

我的问题是:一般来说,这是usecallback()最重要的用法吗?

推荐答案

"组件"就是一个简单的JavaScript函数. "呈现"组件的意思就是"运行函数".

JS函数每次运行时都会重新创建其中的变量,包括函数定义,这一点是正确的.

react 提供的"魔力"避免了看起来像是被重新创造的东西是useState()useMemo()useCallback()等等.这些都不能绕过上面提到的基本JS行为.这些钩子在第一次运行和后续运行(即随后的"呈现")时"缓存"值,如果React发现它的缓存中有一个变量/对象/函数,则它将该值返回给由useState/useMemo/useFunction创建的"新"实例,就像在前一次运行中一样.

现在,在上面的示例中,如果handle属性更改,则它将重新生成子组件,因此将重新呈现它.你至少有两种方法可以避免这种情况:

  1. 定义handleIncrement()时使用useCallback()(如您所做的……但见下文)
  2. 将第二个参数传递给memo()--该函数用于比较组件以前和当前的props ,如果它们相同则返回true(即不呈现).因此,只需将第二个参数设置为() => true,它将永远不会重新生成,也永远不会重新呈现.

现在...你现在的handleIncrement() 你可以使用useCallback(),它依赖于state的值. 但是每次调用handleIncrement(),它都会增加state的值. 因此,这将导致Parent重新呈现,并且使用新值state,useCallback()将重新生成handleIncrement()作为新函数,因为它的依赖项具有新值.

还有……最后一件事:setState(state + 1);是一个糟糕的编码模式.因为setState()是一个异步函数,所以您告诉REACT(好吧,是JavaScript):"在以后的某个时刻,请取当前值state,将其与1相加,然后将其放回state".

这里的问题是,如果在JavaScript开始运行其异步队列之前多次调用setState()……您可能最终会丢失数据!如果state的当前值是7,并且您编码:

setState(state + 1);
setState(state + 100);
setState(state - 2);

然后,当您的组件最终开始重新呈现时,state的值将是5……因为JS被告知要运行7 + 17 + 1007 - 2……最后一个获胜.

每当你有一个状态变量,你想更新它的值,使之相对于它的当前值--无论是数组、对象、字符串、整数,无论什么--然后你想使用"设置状态函数"的"回调签名":setState(currVal => currVal + 1).

该语法告诉JavaScript"在TIMET上运行设置状态函数,获取其当前值,加1,然后将其放回状态变量".

使用后一种方法,如果您拨打setState() setState()0次,每次都会得到正确的答案.在上述条件相同的情况下,state等于7,您可以进行编码:

setState(currVal => currVal + 1);
setState(currVal => currVal + 100);
setState(currVal => currVal - 2);

然后JS会做:7 + 18 + 100setState() - 2.重新渲染时的值将为setState(state + 1).主要区别在于setState(currVal => ....)获得状态变量109的值,而setState(state + 1)setState()被添加到异步队列时获得值state*.

如果您还没有,我强烈建议我的所有朋友(并要求我的所有同事)观看视频JavaScript: Understanding the Weird Parts次,特别是关于同步和异步代码执行的部分(视频描述中有时间链接).

Reactjs相关问答推荐

我的组件在jsx文件中继续重新渲染

如何使用json将购物车数组传递到后台API

条件索引路由

如何在没有 node 模块的情况下利用外部Java脚本文件制作OWL carousel

ReactJs;Reaction-Hook-Form:仅当 Select 了特定 Select 列表选项时才显示文本输入

for each 子级加载父路由加载器

自定义变量默认、聚焦和填充时所需TextField中标签的星号 colored颜色

关于forwardRef,我可以';我不理解第二个用例

在 React 中,为什么不将组件和钩子结合起来呢?

如何使用 React 获取表单中的所有值?

更新对象状态的父数组时记住子组件

我可以在加载器函数中多次 fetch() 并使用一次 useloaderdata() 提取它吗?

如何读取 null 的属性?

图像路径很奇怪,部署 Next.js 应用程序后我看不到任何图像

为什么刷新页面时我的localStorage PET值变成空字符串?

在 React JS 中编辑表格数据

如何使用 React 更改 Material UI 中 ButtonGroup 的 colored颜色 ?

当用户输入相同信息时如何禁用更新

如何修复 Next.js 13 中类型 AppRouterInstance 上不存在 x?

在表格中显示具有自定义声明的用户状态