Uppy与Relay Modern集成:React应用中的高级GraphQL上传

Uppy与Relay Modern集成:React应用中的高级GraphQL上传

【免费下载链接】uppy The next open source file uploader for web browsers :dog: 【免费下载链接】uppy 项目地址: https://gitcode.com/gh_mirrors/up/uppy

在现代React应用开发中,文件上传功能往往需要与GraphQL数据层深度整合。本文将详细介绍如何将Uppy文件上传器与Relay Modern框架无缝集成,构建高效、可靠的文件上传解决方案。我们将通过实际代码示例和最佳实践,帮助开发者解决大文件分块上传、上传状态管理和GraphQL mutations集成等常见挑战。

技术栈概述

Uppy是一个功能强大的开源文件上传器,支持拖放、进度显示、断点续传等特性,通过模块化设计可以灵活扩展。Relay Modern则是Facebook推出的高效GraphQL客户端,专注于性能优化和类型安全。两者结合可以为React应用提供企业级的文件上传体验。

项目核心依赖模块:

集成准备工作

在开始集成前,确保项目中已正确安装所需依赖。典型的package.json配置应包含Uppy相关包和Relay Modern生态:

{
  "dependencies": {
    "@uppy/core": "^3.14.0",
    "@uppy/react": "^3.8.0",
    "@uppy/tus": "^3.1.0",
    "react-relay": "^15.0.0",
    "relay-runtime": "^15.0.0"
  }
}

Uppy基础配置

首先创建Uppy实例,配置必要的插件。以下是一个基础配置示例,来自examples/react/src/App.tsx

import Uppy from '@uppy/core'
import Tus from '@uppy/tus'
import { useState } from 'react'

function App() {
  const [uppy] = useState(() =>
    new Uppy({
      autoProceed: false,
      restrictions: {
        maxFileSize: 10000000, // 10MB
        maxNumberOfFiles: 5,
        allowedFileTypes: ['image/*', 'application/pdf']
      }
    }).use(Tus, {
      endpoint: 'https://your-tus-server.com/files/',
      chunkSize: 5 * 1024 * 1024, // 5MB分块
      retryDelays: [0, 1000, 3000, 5000]
    })
  )
  
  // 组件其余部分...
}

此配置启用了TUS协议支持,适合大文件分块上传,并设置了基本的文件限制。TUS协议提供断点续传能力,即使上传中断,用户也可以从中断处继续,而不必重新上传整个文件。

Relay Modern文件上传链接配置

为了使Relay能够处理文件上传,需要配置GraphQL上传链接。创建一个自定义的Relay环境,使用createUploadLink替代默认的网络层:

import { Environment, Network, RecordSource, Store } from 'relay-runtime'
import { createUploadLink } from 'relay-upload-network-layer'

const uploadLink = createUploadLink({
  uri: '/graphql', // 你的GraphQL API端点
  credentials: 'include',
  headers: {
    'Accept': 'application/json',
  },
})

function fetchQuery(operation, variables) {
  return uploadLink.fetch(operation, variables)
}

const environment = new Environment({
  network: Network.create(fetchQuery),
  store: new Store(new RecordSource()),
})

export default environment

这个配置使Relay能够自动检测mutation中的File对象,并使用multipart/form-data格式发送请求,符合GraphQL上传规范。

构建上传组件

结合Uppy的React组件和Relay的mutation,创建一个完整的文件上传组件。以下是一个集成示例:

import { useCallback } from 'react'
import { useMutation } from 'react-relay'
import { Dropzone, FilesList } from '@uppy/react'
import graphql from 'babel-plugin-relay/macro'

// 定义GraphQL mutation
const UploadFileMutation = graphql`
  mutation FileUploaderMutation($input: UploadFileInput!) {
    uploadFile(input: $input) {
      id
      fileName
      fileSize
      url
    }
  }
`

interface FileUploaderProps {
  uppy: Uppy.Uppy
}

const FileUploader = ({ uppy }: FileUploaderProps) => {
  const [commitMutation] = useMutation(UploadFileMutation)
  
  const handleUpload = useCallback(async () => {
    const files = uppy.getFiles()
    
    for (const file of files) {
      // 获取Uppy上传后的文件URL(假设使用TUS或类似服务)
      const fileUrl = file.url || ''
      
      // 调用Relay mutation
      commitMutation({
        variables: {
          input: {
            fileName: file.name,
            fileSize: file.size,
            fileUrl: fileUrl,
            // 其他元数据...
          }
        },
        onCompleted: (response) => {
          console.log('File uploaded:', response.uploadFile)
          uppy.removeFile(file.id)
        },
        onError: (error) => {
          console.error('Upload mutation failed:', error)
        }
      })
    }
  }, [uppy, commitMutation])
  
  return (
    <div className="file-uploader">
      <Dropzone uppy={uppy} />
      <FilesList uppy={uppy} />
      <button onClick={handleUpload} disabled={!uppy.getFiles().length}>
        完成上传
      </button>
    </div>
  )
}

export default FileUploader

这个组件结合了Uppy的文件选择/拖放界面和Relay的mutation处理,实现了完整的文件上传流程。

状态管理与用户反馈

为提升用户体验,添加上传状态管理和实时反馈。Uppy提供了丰富的事件系统,可以监听上传过程的各个阶段:

useEffect(() => {
  const handleUploadProgress = (file: Uppy.File, progress: number) => {
    console.log(`File ${file.name} progress: ${progress}%`)
    // 更新进度UI
  }
  
  const handleUploadSuccess = (file: Uppy.File) => {
    console.log(`File ${file.name} uploaded successfully`)
    // 显示成功通知
  }
  
  const handleUploadError = (file: Uppy.File, error: Error) => {
    console.error(`File ${file.name} upload failed:`, error)
    // 显示错误通知
  }
  
  uppy.on('upload-progress', handleUploadProgress)
  uppy.on('upload-success', handleUploadSuccess)
  uppy.on('upload-error', handleUploadError)
  
  return () => {
    uppy.off('upload-progress', handleUploadProgress)
    uppy.off('upload-success', handleUploadSuccess)
    uppy.off('upload-error', handleUploadError)
  }
}, [uppy])

通过这些事件处理函数,可以构建详细的上传进度指示器和用户通知系统。

高级优化策略

分块上传与断点续传

对于大文件上传,推荐使用Uppy的Tus插件,它实现了TUS协议,支持断点续传和分块上传:

uppy.use(Tus, {
  endpoint: 'https://your-tus-server.com/files/',
  chunkSize: 8 * 1024 * 1024, // 8MB分块
  retryDelays: [0, 1000, 3000, 5000],
  parallelUploads: 2, // 并行上传2个分块
  metadata: (file) => ({
    filename: file.name,
    filetype: file.type,
  }),
})

与Relay缓存集成

确保文件上传后更新Relay缓存,保持UI与后端数据同步:

commitMutation({
  // ...其他配置
  updater: (store) => {
    // 获取mutation结果
    const payload = store.getRootField('uploadFile')
    if (!payload) return
    
    // 将新上传的文件添加到缓存中的文件列表
    const user = store.get('current-user-id')
    if (user) {
      const files = user.getValue('files') || []
      user.setValue('files', [...files, payload.getDataID()])
    }
  }
})

完整示例应用

将以上组件整合到一个完整的React应用中。以下是一个应用入口示例,来自examples/react/src/App.tsx

import Uppy from '@uppy/core'
import { UppyContextProvider } from '@uppy/react'
import UppyTus from '@uppy/tus'
import FileUploader from './FileUploader'
import environment from './relay-environment'
import { RelayEnvironmentProvider } from 'react-relay'

function App() {
  const [uppy] = useState(() =>
    new Uppy({
      debug: true,
      autoProceed: false,
      restrictions: {
        maxFileSize: 50 * 1024 * 1024, // 50MB
        allowedFileTypes: ['*']
      }
    }).use(UppyTus, {
      endpoint: 'https://tusd.tusdemo.net/files/',
    })
  )
  
  return (
    <RelayEnvironmentProvider environment={environment}>
      <UppyContextProvider uppy={uppy}>
        <main className="app-container">
          <h1>文档管理系统</h1>
          <FileUploader uppy={uppy} />
          {/* 其他应用内容 */}
        </main>
      </UppyContextProvider>
    </RelayEnvironmentProvider>
  )
}

export default App

这个示例展示了如何在应用顶层设置Uppy和Relay环境,使文件上传功能在整个应用中可用。

常见问题与解决方案

CORS问题

文件上传经常遇到跨域资源共享(CORS)问题。确保服务器端正确配置了CORS头:

Access-Control-Allow-Origin: https://your-frontend-domain.com
Access-Control-Allow-Methods: GET, POST, PUT, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true

大文件处理

对于特别大的文件(1GB以上),建议:

  1. 减小分块大小(如2-5MB)
  2. 实现上传队列,限制并发上传数量
  3. 添加暂停/继续功能

Uppy的Tus插件已内置这些功能,只需正确配置即可:

.use(Tus, {
  endpoint: 'https://your-tus-server.com/files/',
  chunkSize: 2 * 1024 * 1024, // 2MB分块
  parallelUploads: 1, // 串行上传
  resume: true, // 启用续传
})

类型安全

使用TypeScript增强类型安全,为Uppy和Relay类型创建定义文件:

// types/uppy-relay.d.ts
import type Uppy from '@uppy/core'

declare module '@uppy/core' {
  interface File {
    // 添加自定义文件元数据类型
    projectId?: string
    tags?: string[]
  }
}

// Relay mutation变量类型
interface UploadFileInput {
  fileName: string
  fileSize: number
  fileUrl: string
  projectId?: string
}

总结与最佳实践

Uppy与Relay Modern的集成提供了强大的文件上传解决方案,特别适合需要处理复杂文件上传场景的React应用。以下是一些关键最佳实践:

  1. 模块化配置:将Uppy和Relay配置分离为独立模块,提高可维护性
  2. 错误处理:实现多层错误处理,包括网络错误、服务器错误和业务逻辑错误
  3. 性能优化:使用分块上传、并行控制和缓存策略优化大文件上传
  4. 用户体验:提供清晰的进度指示、错误反馈和操作指引
  5. 测试覆盖:为上传流程编写单元测试和集成测试,确保可靠性

通过本文介绍的方法,开发者可以构建出健壮、高效的文件上传系统,满足现代Web应用的需求。更多高级功能和配置选项,请参考Uppy官方文档和Relay Modern文档。

扩展阅读

【免费下载链接】uppy The next open source file uploader for web browsers :dog: 【免费下载链接】uppy 项目地址: https://gitcode.com/gh_mirrors/up/uppy

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值