You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ReactJS Uppy技术问题:状态变更后Uppy重置状态导致图片不显示,如何预填充/预加载图片

Hey there! Let's work through your Uppy issues step by step. The core problem you're hitting is that your Uppy instance gets reinitialized every time your component state changes, which wipes out any uploaded files. Let's fix that first, then cover how to properly add/display images and implement preloading.


1. Stop Uppy from resetting on component state changes

The key here is to persist your Uppy instance across component re-renders using React's useRef—this keeps the instance alive instead of creating a new one every time your component updates. Here's how to adjust your code:

import { useRef, useEffect } from 'react';
import Uppy from '@uppy/core';
import XHRUpload from '@uppy/xhr-upload';
import Webcam from '@uppy/webcam';
import Dashboard from '@uppy/react';

function YourComponent() {
  // Use useRef to keep the Uppy instance stable across re-renders
  const equipmentUppyRef = useRef(null);
  const data = /* Your existing data state here */;

  useEffect(() => {
    // Initialize Uppy ONLY once when the component mounts
    if (!equipmentUppyRef.current) {
      const uppy = new Uppy({
        id: 'equipment_uppy',
        restrictions: { allowedFileTypes: ['image/*', 'video/*'] },
        autoProceed: false
      });

      uppy.use(XHRUpload, {
        endpoint: `${process.env.REACT_APP_SITE_URL}/api/auth/uploadavintakeimages`,
        formData: true,
        fieldName: 'files[]',
        headers: { Authorization: `Bearer ${localStorage.getItem('accessToken')}` }
      });
      uppy.use(Webcam);

      uppy.on('file-added', (file) => {
        uppy.setFileMeta(file.id, { 
          type: file.source, 
          avintakeid: data.id 
        });
      });

      equipmentUppyRef.current = uppy;
    }

    // Update dynamic values (like auth token or avintakeid) without resetting Uppy
    const uppy = equipmentUppyRef.current;
    if (uppy) {
      // Refresh auth header if access token changes
      const uploadPlugin = uppy.getPlugin('XHRUpload');
      if (uploadPlugin) {
        uploadPlugin.setOptions({
          headers: { Authorization: `Bearer ${localStorage.getItem('accessToken')}` }
        });
      }
      // Update avintakeid meta for all files if data.id changes
      uppy.getFiles().forEach(file => {
        uppy.setFileMeta(file.id, { ...file.meta, avintakeid: data.id });
      });
    }

    // Clean up Uppy instance when component unmounts to avoid memory leaks
    return () => {
      if (equipmentUppyRef.current) {
        equipmentUppyRef.current.close();
        equipmentUppyRef.current = null;
      }
    };
  }, [data.id]); // Re-run effect only when data.id changes

  return (
    <Dashboard 
      uppy={equipmentUppyRef.current} 
      id='equipment_location_image' 
      width='100%' 
      height='300px' 
      plugins={['Webcam']} 
    />
  );
}

2. Adding and displaying uploaded images correctly

The Uppy Dashboard will automatically display previews for added/uploaded images, but if you want to show them outside the Dashboard (like in a gallery), you can fetch the file list from Uppy and render them directly:

// Inside your component
const uploadedImages = equipmentUppyRef.current?.getFiles()
  .filter(file => file.status === 'upload-success');

// In your JSX
return (
  <>
    <Dashboard {/* ... your existing Dashboard props ... */} />
    <div className="uploaded-image-gallery">
      {uploadedImages?.map(file => (
        <img
          key={file.id}
          src={file.preview}
          alt={file.name}
          style={{ width: '120px', height: '120px', objectFit: 'cover', margin: '8px' }}
        />
      ))}
    </div>
  </>
);

3. Pre-filling and preloading existing images

If you need to load images that were already uploaded (e.g., on an edit page), use Uppy's addFile method to inject these files into the instance. Mark them as "already uploaded" so Uppy doesn't try to re-send them:

useEffect(() => {
  // ... existing Uppy initialization code ...

  // Fetch and preload existing images from your API
  const preloadExistingImages = async () => {
    if (!data.id) return;
    
    // Replace with your API call to get existing images for the current data.id
    const existingImages = await fetch(`/api/auth/getavintakeimages/${data.id}`)
      .then(res => res.json());

    existingImages.forEach(img => {
      equipmentUppyRef.current.addFile({
        id: img.id, // Unique ID for the existing file
        name: img.filename,
        type: img.mimeType,
        preview: img.url, // URL to the hosted image for preview
        meta: {
          avintakeid: data.id,
          url: img.url, // Store the existing URL for reference
          type: 'existing' // Optional: mark to handle differently (e.g., delete logic)
        },
        status: 'upload-success' // Tell Uppy this file is already uploaded
      });
    });
  };

  // Run preload after Uppy is initialized and data.id is available
  if (equipmentUppyRef.current && data.id) {
    preloadExistingImages();
  }

  // ... cleanup code ...
}, [data.id]);

If you want users to be able to delete preloaded images, add a listener for the file-removed event to trigger your API's delete endpoint:

uppy.on('file-removed', async (file) => {
  if (file.meta.type === 'existing') {
    // Call your API to delete the existing image
    await fetch(`/api/auth/deleteavintakeimage/${file.meta.url}`, { method: 'DELETE' });
  }
});

内容的提问来源于stack exchange,提问作者Chirag Kasera

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 10:32:36