我创建了一个condesandbox,在这里重新创建了这个问题:https://codesandbox.io/s/agitated-tree-dq8rx?file=/src/App.js
沙箱重新创建了一个组件的功能,该组件显示了可以选择的空图像预览缩略图列表。
当用户上传图像并且返回downloadUrl
时,更新当前选择的图像的图像缩略图。useEffect
挂钩依赖于downloadUrl
,因此每次上传新图像并返回downloadUrl
时都会调用它。我用一个按钮模仿了这个功能,每次点击它都会返回一个新的URL。
如果我包含了依赖项的完整列表,downloadUrl
会立即应用于单击的下一个区域。这不是我想要的。我希望能够选择下一个图像缩略图并为其分配不同的downloadUrl
。只有当我排除了"project"one_answers"selectedZoneIndex"依赖项时,这才能正常工作。
我试图通过使用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])
据我所知,您根本不需要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);
};