在React Redux存储中存储文件对象的最佳方法是什么?(从DropZone上传文件?)

11

我目前正在使用Material Ui的dropzone上传多个文件,想知道将文件添加/更新到redux store的最佳方法。当"onChange"触发时,我正在执行dispatch操作,该操作返回dropzone上的所有文件并将整个文件数组(具有文件对象)存储到redux状态中进行更新。

请告诉我是否有更好的处理方式。


你的问题非常开放,你需要对这些文件做什么?是需要处理还是直接发送到服务器?你使用的React和Redux版本是什么? - Victor Carrera
1
我需要直接将文件发送到服务器的post端点。我正在使用React 16.13.1和Redux 4.0.5。 - dev0864
在这种情况下最好不要使用redux store。你可以在组件中直接调用API post。还有其他类似于dropzone的库,你可以看一下https://github.com/pqina/filepond,这个库可以直接post。store更适用于在组件之间共享可序列化对象。 - Victor Carrera
3个回答

11

那么只需将其存储在本地状态中,然后发送到操作并进行API调用?我想这是唯一的方法,而不必将其添加到redux store中。听起来不错吗? - dev0864
大体上是这样的。除非有很多其他组件确实需要访问那些文件,否则没有什么好的理由将它们放在Redux存储中。 - markerikson
还有一个问题,如果没有提交按钮,如何使API调用以将文件发送到服务器的空闲方式在哪里。方法“onChange”给出了放置区中的所有文件,而方法“onDrop”仅给出了当前正在拖放的文件。我想在“onDrop”上进行API调用,请告诉我。 - dev0864

6

我遇到类似的问题,最终使用了这个:

URL.createObjectURL(file)

它返回一个类似于 blob:http://example.com/f331074d-a7f3-4972-9c37-96b490a4dd96 的URL,它只是一个字符串,可以在 img 标签的 src 属性中使用。不确定 Material Ui dropzone 返回什么,但这适用于由 <input type="file" /> 返回的文件对象。

3
你会如何使用此方法将文件发送到后端? - Chandan
1
我认为这个解决方案只适用于想要预览图像的情况。你无法访问实际文件。 - Arian Nargesi
要从URI检索文件/ Blob,请参见https://dev59.com/lGct5IYBdhLWcg3wuPq6 - Rodrigo Amaral

0

TLDR: 这里解释了如何在TypeScript中使用React Context来解决问题,而不使用Redux(如果你更喜欢JavaScript,可以转换回去)。希望这不会偏离主题,因为我之前也遇到过这个问题。

在处理表单中的文件上传的特定情况下,我建议不要使用状态管理器(非序列化数据),而是使用React Context。通过这种方式,你可以将文件/文件数组(多文件上传)传递到任何需要它们的地方(当然是在提供者的范围内),而不必将props一层层地传递到所需的组件。

我确信有其他解决这个问题的方法,但是我越是使用React上下文,就越能理解其内部工作原理和与状态管理器相比的使用原则,感觉就像是一步之遥。但是让我们记住,需求范围稍有不同,因为我们想要上传一些文件并将其存储在浏览器中,甚至在发送之前进行预览,就像#jetpackpony所描述的那样,接下来的内容会很有用:
想象一下,我们想要用上下文包装一个对话框组件,这样子组件就可以在其父组件的范围内接收和处理数据。

创建上下文并导出我们的提供者:

DialogContextProvider.tsx

import { createContext, useMemo, useState } from 'react'

interface DialogContextValues {
  attachments: File[]
  setAttachments: React.Dispatch<React.SetStateAction<File[]>>
}

export const DialogContext = createContext<DialogContextValues | undefined>(undefined)

const DialogContextProvider = ({ children }: { children: JSX.Element }) => {
  const [attachments, setAttachments] = useState<File[]>([])

  const dialogContextValue = useMemo(
    () => ({ attachments, setAttachments }),
    [attachments, setAttachments],
  )

  return <DialogContext.Provider value={dialogContextValue}>{children}</DialogContext.Provider>
}

export default DialogContextProvider

设置上下文

作为组件的父级,可以获取/设置其数据。

SomeUIComponent.tsx

import DialogContextProvider from './DialogContextProvider'

export const SomeUIComponent = () => (
  <div>
    <h2>This is out of context</h2>
    <DialogContextProvider>
      <SomeComponentWhichUsesContext />
      <AnotherComponentWhichUsesContext />
    </DialogContextProvider>
  </div>
)

上下文钩子的使用

此外,我们可以使用自定义钩子在代码中更加流畅地检索数据。

useDialogContext.ts

import { useContext } from 'react'

import { DialogContext } from './DialogContextProvider'

// Custom hook to access the Tone.js context
const useDialogContext = () => {
  const context = useContext(DialogContext)
  const attachments = context?.attachments || []
  const setAttachments = context?.setAttachments || (() => [])

  if (!context) {
    throw new Error('useDialogContext must be used within a Dialog')
  }

  return { attachments, setAttachments }
}

export default useDialogContext

稍后,您可以像这样使用您传递给上下文的值。
const { attachments, setAttachments } = useDialogContext()

请注意,在您的应用程序较小的范围内,您应该更倾向于使用React Context而不是状态管理器。因为相比于配置良好的状态管理器,React Context很可能会触发更多的重新渲染,并且缺乏像单向数据流和可预测的集中状态这样的优秀特性。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接