【问题标题】:How can I make this React useEffect hook work without excluding some dependencies?如何在不排除某些依赖项的情况下使这个 React useEffect 挂钩工作?
【发布时间】:2020-11-21 03:35:05
【问题描述】:

我在这里创建了一个 condesandbox 来重现这个问题:https://codesandbox.io/s/agitated-tree-dq8rx?file=/src/App.js

沙盒重新创建了一个组件的功能,该组件显示一个可以选择的空图像预览缩略图列表。

当用户上传图片并返回downloadUrl时,当前选中图片的图片缩略图会更新。 useEffect 挂钩依赖于 downloadUrl,因此每次上传新图像并返回 downloadUrl 时都会调用它。我用一个按钮模仿了这个功能,每次点击它都会返回一个新的 URL。

如果我包含完整的依赖项列表,downloadUrl 会立即应用于单击的下一个区域。这不是我想要的。我希望能够选择下一个图像缩略图并为其分配不同的downloadUrl。仅当我排除“项目”和“选定区域索引”依赖项时,这才可以正常工作。

我试图通过使用useReducer 钩子和调度函数来解决这个问题。这成功地删除了依赖关系,但是调度函数的结果在 useEffect 钩子中不可用,所以我不能使用新对象来更新项目。我在这里做了一个例子:https://codesandbox.io/s/jovial-sara-ofoh1?file=/src/App.js(newProject 在控制台中是undefined

对于如何在遵循最佳实践(不排除应包含的依赖项)的同时解决此问题的任何建议,我将不胜感激。

useEffect(() => {
  const onUpdateProject = async (newProject) => {
    try {
      await updateDatabase(newProject)
      return "updated"
    } catch (error) {
      return "error"
    }
  }
  if (downloadUrl) {
    setSelectedZoneImageUrl(downloadUrl);

    // Update Zone with downloadUrl
    const updatedZones = zones.slice();
    updatedZones[selectedZoneIndex]["imageDownloadUrl"] = downloadUrl;

    // Create new project with updated zone
    const newProject = {
      ...project,
      zones: updatedZones,
    };

   onUpdateProject(newProject);
  }
}, [downloadUrl, selectedZoneIndex, project, zones])

【问题讨论】:

  • 我尝试了你的第一个沙盒和printed all the dependencies。我看到project 已成功传递给useEffect。另一方面,在触发updateServer 时存在无限循环。如果我随后更改区域,则会立即应用该 url。是这个问题吗?
  • 您的评论让我意识到onUpdateProjectupdateDatabase 不是证明问题所必需的。在我的实际应用程序中,我在异步函数调用中使用 useEffect 钩子的结果,因此我尝试模仿它来演示使用 dispatch 的问题。我已将它们从我的示例中删除,并且无限循环消失了,但立即应用 url 的问题仍然存在。谢谢。

标签: reactjs react-hooks


【解决方案1】:

据我所知,您根本不需要useEffect。也许您的实际用例使这不可行,但是如果您摆脱这种影响并将所有逻辑放入 newDownloadUrl 处理程序中,您的原始代码示例似乎可以按预期工作。如果这一切都发生在一个地方,则无需对状态更改做出反应。

我还发现了您处理 zones 数组的方式的另一个问题 - 因为它是一个对象数组,您需要单独克隆每个对象,否则它们将保留它们的引用。在 updateDatabase 中调用 setter 之前,您的状态正在发生变化:

const newDownloadUrl = () => {
    const onUpdateProject = async newProject => {
      try {
        await updateDatabase(newProject);
        return "updated";
      } catch (error) {
        return "error";
      }
    };

    const newUrl = "www." + Math.round(Math.random() * 100) + ".com";
    setDownloadUrl(newUrl);
    setSelectedZoneImageUrl(newUrl);

    // Update Zone with downloadUrl
    const updatedZones = zones.slice().map(z => ({...z}));
    updatedZones[selectedZoneIndex]["imageDownloadUrl"] = newUrl;

    // Create new project with updated zone
    const newProject = {
      ...project,
      zones: updatedZones
    };

    onUpdateProject(newProject);
  };

【讨论】:

  • 我认为我不能使用这种方法。需要 useEffect 是因为在我的真实应用程序中,downloadUrl 是由另一个组件调用的自定义挂钩返回的值。 newDownloadUrl 按钮只是我尝试在沙箱中重新创建该功能,其中为每个新的downloadUrl 调用 useEffect。感谢您提供有关改变状态的建议。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-18
  • 2020-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多