使用 Redux Thunk 时正确理解 useEffect 中的依赖数组

Posted

技术标签:

【中文标题】使用 Redux Thunk 时正确理解 useEffect 中的依赖数组【英文标题】:Proper understanding of dependency array in useEffect when working with Redux Thunk 【发布时间】:2021-10-28 20:35:15 【问题描述】:

我开始学习 Redux 和 thunk 库。

我有一个包含函数的 Actions.js:

export const fetchInventory = (user_id) => 
return (dispatch) => 
    dispatch(fetchInventoryData());
    fetch("url", 
      method: "POST",
      headers: 
        Accept: "application/json",
        "Content-Type": "application/json",
      ,

      //make sure to serialize your JSON body
      body: JSON.stringify( user_id ),
    )
      .then((res) => res.json())
      .then((res) => 
        saveInventory(res);
        dispatch(fetchInventorySuccess(res));
      )
      .catch((err) => dispatch(fetchInventoryFailure(err)));
  ;
;

和一个带有useEffect的Container.js如下:

  useEffect(() => 
    if (inventory.inventoryData.length > 0) return;
    else if (user_id) fetchInventory(user_id);
    else return [];
  , [user_id]);

EsLint 警告我在依赖数组中缺少 fetchInventory 和 inventory。但是,由于库存是此获取将更新的状态,包括它会使我们陷入无限获取。此外,这里需要的 user_id 是来自之前的获取请求的东西。在这种情况下,什么会进入依赖数组,为什么?

【问题讨论】:

【参考方案1】:

inventory 当然应该包含在依赖数组中,因为它在钩子回调中引用也可能是 fetchInventory 动作创建者,出于同样的原因)。

我认为这里的问题是不正确的保护子句(即条件),您正在调用更新状态(和依赖项)的回调。

if-else-if-else 是问题所在。当第一个条件失败时,因为inventory.inventoryData.length不为零,检查第二个条件,果然有一个定义的user_id值并调用回调。

据我所知,您想要的条件是“如果有没有库存数据AND 一个用户ID,然后获取库存,否则什么都不做”。

尝试简化您的条件和分支因子。

useEffect(() => 
  if (!inventory.inventoryData.length && user_id) 
    fetchInventory(user_id)
  
, [fetchInventory, inventory.inventoryData, user_id]);

【讨论】:

谢谢你真的成功了。我很难理解这一点,您能否进一步详细说明为什么我的现有版本会产生与您相同的行为以及为什么您的版本当然是正确的做法以及像我一样这样做的后果? @SeymurMammadov 是if-else-if-else,当第一个条件失败时,因为inventory.inventoryData.length不为零,所以检查第二个条件,果然有一个定义的user_id值和回调被调用。如果您将第二个条件塞进第一个条件的块中,那么我怀疑它会起作用。最后一个else 什么都不做。我更新了我的答案,也包括了解释。 在您收到名为 modal 的对象道具并在组件中执行此操作的场景中如何: const [activity, setActivity] = useState( interaction: [], title: "", body: "", company_id: 162, ); useEffect(() => setActivity( ...activity, ...modal ); , [modal]); ESlint 抱怨并说要添加活动,但这样做会引发无限循环。我的问题更适合于为什么 ESLint 在这里抱怨,而你显然无法添加它。 @SeymurMammadov 除了将 props 存储到本地组件状态中有点反模式之外,我认为没有任何问题,因为 activity 状态中的任何内容都不在效果的依赖数组中。哦,是的,你应该使用功能状态更新来更新之前的状态,即useEffect(() => setActivity(activity => ( ...activity, ...modal )); , [modal]);。这消除了回调中对activity 的外部依赖。 @SeymurMammadov linter 不是很亮,也不一定“足够聪明”,无法看到钩子回调中引用的值实际上 由回调中调用的函数更新。

以上是关于使用 Redux Thunk 时正确理解 useEffect 中的依赖数组的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Typescript 中使用 redux-thunk 使用 ThunkAction 正确键入 thunk?

Redux-thunk 异步调用和状态

使用 ConnectedProps 和 redux-thunk 获取正确的调度类型

使用多个中间件时在 redux 存储上正确键入 dispatch

在redux和redux thunk中使用异步调度传递参数

无法理解 Redux-thunk 中间件