正确运行动态项列表的突变



我的用例是,给定一个用户输入是一个文件数组,应用程序并行地启动所有文件的上传,并为正在进行的每个上传显示一个组件。我尝试使用@tanstack/react-queryuseMutation钩子来做到这一点,因为你不能有一个钩子数组,我做了这样的事情:

async function uploadFile(file) { ... }
// Supposed to start the file upload on mount.
function UploadingFile({file, ...}) {
const { mutate } = useMutation(() => uploadFile(file), ...);
// This doesn't work in React strict/concurrent mode
useEffect(() => {
mutate();
}, [mutate]);
}
function UploadingFileList({files, ...}) {
return (
<div>
{files.map((file, index) => (
<UploadingFile key={index} file={file} />
)};
</div>
);
}

useEffect在React严格/并发模式下触发两次(我理解为什么会发生这种情况)。我考虑了两种可能的解决方案:

  1. 实现一些hack,使useEffect只火一次。有很多关于使用useRef的例子。这种方法的问题是,它是一个黑客。
  2. 使用useQuery/useQueries代替useMutation,它已经自动触发了。这种方法的问题是,它需要查询键,但文件上传操作没有固有的唯一键。解决这个问题的一种方法可能是为每个文件上传使用随机生成的ID。

这两种方法似乎都很粗糙,所以我想听听其他人的意见。有没有更地道的方法来达到我想要的?

你可以尝试使用一个空数组作为第二个参数的useEffect钩子,这将导致效果只运行一次。

如何在UploadingFile组件中使用useEffect钩子启动文件上传过程的示例:

function UploadingFile({file, ...}) {
const { mutate } = useMutation(() => uploadFile(file), ...);
useEffect(() => {
mutate();
}, []);  // This will cause the effect to run only once
}

或者,你可以在UploadingFile组件中使用useMutation钩子来创建一个函数来启动文件上传过程,然后从UploadingFile组件的render方法中调用这个函数:

function UploadingFile({file, ...}) {
const [mutate, { isLoading, isError }] = useMutation(() => uploadFile(file), ...);
const startUpload = () => {
mutate();
}
return (
<div>
{isLoading ? 'Uploading...' : 'Ready to upload'}
{isError && 'An error occurred'}
<button onClick={startUpload}>Start upload</button>
</div>
);
}

这种方法不会有在严格/并发模式下多次触发useEffect钩子的相同问题,因为mutate函数不会从效果内部调用。

实现这一点的方法是useEffect中触发突变,而是在触发用户上传文件的事件处理程序中触发突变。

你当然可以连续多次调用mutate,或者你可以有一个突变,只触发多次调用Promise.all()

让我们假设事件处理程序是一个点击,接收一个数组:

const { mutate } = useMutation({
mutationFn: files => {
return Promise.all(files.map(uploadFile))
}
})
<MyUploadComponent 
onClick={(files) => mutate(files)}
/>

相关内容

  • 没有找到相关文章

最新更新