javascript - 展开和折叠后保持状态 |导致 React 状态更新错误

标签 javascript reactjs react-hooks use-effect setstate

我开发了一个上传功能,在 Accordion 中上传组件。现在我想保留 Accordion 折叠和展开时上传到系统中的数据/文件。

现在我可以保留文件,但删除它们会引发错误。

错误:

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

设计

  1. 父组件/(类组件)[parentState]
  2. 子组件/Functional(上传)[维护本地状态],发送父组件(工作)所需的数据
  3. 为了保留状态,在 Accordion 折叠和展开后,通过回调函数将所有[本地状态]数据移动到父状态。
  4. 在组件上挂载(功能组件),获取所有数据并更新本地状态
  5. 删除文件(打开和关闭 Accordion 后),出现上述错误。

代码

/** set the state locally from parent state 
 * component did mount
 */
useEffect(() => {
 
  
  if (parentState[`${field}acceptedFiles`]) {
    setAcceptedFiles([...parentState[`${field}acceptedFiles`]]);
  }
  if (parentState[`${field}rejectedFiles`]) {
    console.log('REJECTED FILES', parentState[`${field}rejectedFiles`]);
    setRejectedFiles([...parentState[`${field}rejectedFiles`]]);
  }

}, []);


/** maintain the state in parent state
 * this is used retain the state from parent state
 */
useEffect(() => {
  const afile = {
    [`${field}acceptedFiles`]: acceptedFiles
  };
  onChange(afile);
}, [acceptedFiles]);

useEffect(() => {
  const rfile = {
    [`${field}rejectedFiles`]: rejectedFiles
  };
  onChange(rfile);
}, [rejectedFiles]);



/** deleting the rejected files, removing them from UI */
const deleteRejectedFile = (uuid) => {
  setRejectedFiles((updatedRejectedFiles) => {
    return updatedRejectedFiles.filter(rejectedFile => rejectedFile.uuid !== uuid);
  });
}

/** deleting the accepted files, removing them from UI and removing from attachments
 * Send back uploadAttachments to parent state */
const deleteAcceptedFile = (uuid) => {
  setAcceptedFiles((updatedAcceptedFiles) => {
    return updatedAcceptedFiles.filter(acceptedFile => acceptedFile.uuid !== uuid);
  });
}

const handleRejectedFiles = (rejected, docTypeError) => {
  const files = rejected.map(file => {
    const uuid = getUUID();
    return {
    name: file.name,
    uuid,
    rightIconItems: {
      onIconClick: () => deleteRejectedFile(uuid)
    },
  }});
  setRejectedFiles([...rejectedFiles, ...files]);
}

const handleAcceptedFiles = (accepted) => {
  const files = accepted.map((file) => {
    const uuid = getUUID();
    const { PENDING, INFO } = constants;
    return {
      ...file,
      file: file,
      uuid,
      rightIconItems: {
        onIconClick: () => deleteAcceptedFile(uuid)
      }
    }
  })
  setAcceptedFiles([...acceptedFiles, ...files]);
}

const onFileSelected = (accepted, rejected) => {
  handleAcceptedFiles(accepted);
  handleRejectedFiles(rejected);
};

return (
  <DragAndDropContainer>
    <FileSelector 
      onFileSelected={onFileSelected}
      acceptedFiles={acceptedFiles}
      rejectedFiles={rejectedFiles}
    />
  </DragAndDropContainer>
);

设计 dataflow

更新了错误

错误出在 delete 函数中,因为 accordion 已关闭,组件已卸载,但 setState 仍指向其旧引用 [scope]。

有没有办法将 setstate 指向新创建的组件,而不是在不将状态移动到父函数的情况下指向未安装的组件。

/** deleting the rejected files, removing them from UI */
const deleteRejectedFile = (uuid) => {
  setRejectedFiles((updatedRejectedFiles) => {
    return updatedRejectedFiles.filter(rejectedFile => rejectedFile.uuid !== uuid);
  });
}

最佳答案

此错误是由于引用删除方法引起的。 deleteRejectedFiledeleteAcceptedFile 函数的 setstate 方法指向已卸载的组件,而不是指向已安装的组件。

所以我创建了一个新的图标引用

    useEffect(() => {
      if (parentState[`${field}acceptedFiles`]) {
        const newAcceptedReferences = parentState[`${field}acceptedFiles`].map((accepted) => {
          const rightIconItems = {
            onIconClick: () => deleteAcceptedFile(accepted.uuid)
          };
          return {
            ...accepted,
            rightIconItems
          }
        });
        setAcceptedFiles(newAcceptedReferences);
      }
    
      if (parentState[`${field}rejectedFiles`]) {
        const newRejectedReferences = parentState[`${field}rejectedFiles`].map((rejected) => {
          const rightIconItems = {
            onIconClick: () => deleteRejectedFile(rejected.uuid)
          };
          return {
            ...rejected,
            rightIconItems
          }
        });
        setRejectedFiles(newRejectedReferences);
      }
    }, []);

关于javascript - 展开和折叠后保持状态 |导致 React 状态更新错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73487308/

相关文章:

javascript - Grunt uglify 将字符串 "undefined"视为关键字 undefined

javascript - 如何在 Angular 中使用 *ngFor 动态调用所有图像并显示?

javascript - 如何使表体垂直滚动的 Material -ui?

javascript - 默认情况下尝试使用 state react es6 隐藏 <p> 标签

javascript - 无法在 Gulp 项目中导入 React Router Dom

reactjs - 尝试实现 useEffect 时出现奇怪的错误

javascript - 重新加载页面时出现状态未定义错误

javascript - 具有动态 HTML 模板的 AngularJS 递归指令

javascript - 单击 R Leaflet 中的 'plugin' 脉冲标记时添加弹出窗口

javascript - 当在另一个函数中调用调用它的函数时,React Hooks 状态无法正常工作