【已解决】The ‘chartInit‘ function makes the dependencies of useEffect Hook……

专栏【React–从基础到实战】

报错内容:The ‘chartInit’ function makes the dependencies of useEffect Hook (at line 38) change on every render.

如果你正在使用React Hooks,尤其是useEffect这个Hook,你一定会遇到这个问题。

The ‘functionName’ function makes the dependencies of useEffect Hook (at line X) change on every render. Move it inside the useEffect callback. Alternatively, wrap the definition of ‘functionName’ in its own useCallback() Hook. (react-hooks/exhaustive-deps)

将这个报错翻译为中文,大致意思是:

‘functionName’ 函数使 useEffect Hook(在第 X 行)的依赖关系在每次渲染时都发生变化。将它移到 useEffect 回调中。或者,将 ‘functionName’ 的定义包装在它自己的 useCallback() Hook 中。(react-hooks/exhaustive-deps)

其实,在这段报错中,已经告诉了我们报错的根本原因以及两种解决方法。我们逐步来看一下。

问题的根本原因

为了说明这个报错的原因,我们手写一个简单例子,来触发这个报错:

function App() {
  const [count, setCount] = useState(0);

  const logCount = () => {
    console.log(count);
  };

  useEffect(() => {
    logCount();
  }, [logCount]);

  return <div>{count}</div>;
}

在这个简单的App组件当中,存在一个自己的状态:count,我们想要做的仅仅是,当count状态改变的时候,都把当前的count打印到控制台当中。

这个时候,控制台就会报一个这样的错误:

The ‘logCount’ function makes the dependencies of useEffect Hook (at line 10) change on every render. Move it inside the useEffect callback. Alternatively, wrap the definition of ‘logCount’ in its own useCallback() Hook. (react-hooks/exhaustive-deps).

这段代码中,useEffect的依赖项是这个logCount方法,我们一般会觉得,这个方法一直都没有被改变——渲染的都是相同的函数。但是,事实上真的是这样的吗??

我们先来看这样的两个例子:

console.log({ name: 'Donna' } === { name: 'Donna' });
// false
const fn1 = () => 'Donna';
const fn2 = () => 'Donna';

console.log(fn1 === fn2);
// false

其实,JavaScript 相等性是基于引用相等性工作的。也就是说,对象只有在它们引用内存中的相同对象时才彼此相等。这就是为什么我们最终会得到这样的结果。

这也就正好说明了,上面的useEffect中的logCount会在每个组件渲染中重新创建,因此始终与前一次渲染期间创建的上一个logCount不相同。

那么,如何解决这个问题呢?

解决问题的方法

其实,在报错中已经告诉了我们如何解决这个问题。在这里,运用这个简单的小案例,来解决这个错误。

方法一:将它移到 useEffect 回调中

Move it inside the useEffect callback.

这个相当简单:我们获取logCount函数并将其移动到useEffect钩子中。由于logCount现在在useEffect钩子中,我们不再需要它在依赖数组中。但是,由于logCount依赖于count变量,我们必须将count变量添加到依赖数组中。

function App() {
  const [count, setCount] = useState(1);

  useEffect(() => {
    const logCount = () => {
      console.log(count);
    };
    logCount();
  }, [count]);

  return <div className="App">foo</div>;
}

方法二:将 ‘functionName’ 的定义包装在它自己的 useCallback() Hook 中

Alternatively, wrap the definition of ‘functionName’ in its own useCallback() Hook.

import { useState, useEffect, useCallback } from 'react';

function App() {
  const [count, setCount] = useState(1);

  const logCount = useCallback(() => {
    console.log(count);
  }, [count]);

  useEffect(() => {
    logCount();
  }, [logCount]);

  return <div className="App">foo</div>;
}

现在我们已经将logCount函数包装在一个useCallback钩子中,它将在每次渲染中保持相同的内存引用——除非它的依赖数组中的某些内容发生了变化。在这种情况下,我们添加count到依赖数组。我们需要在计数更新时更新函数,否则我们的效果将无法运行。

评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

codeMak1r.小新

感谢大佬的资瓷!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值