Предварительный просмотр загрузки файлов React исчезает при переключении вкладок (состояние сохраняется)Javascript

Форум по Javascript
Ответить
Anonymous
 Предварительный просмотр загрузки файлов React исчезает при переключении вкладок (состояние сохраняется)

Сообщение Anonymous »

Я строю систему загрузки файлов в моем приложении React, где пользователи могут загружать видео, изображения или субтитры. Файлы загружаются с использованием пользовательского компонента , который генерирует предварительный просмотр выбранного файла с использованием url.createObjecturl () . Однако, когда я переключаю вкладки и возвращаюсь в раздел загрузки файла, предварительный просмотр файла исчезает, но URL -файл все еще существует в состоянии React. < /P>
Что я хочу: < /p>

✅ Я хочу предварительный просмотр файла. Должен
загрузить из URL без повторной загрузки файла. < /li>
✅ < /li>
< /ol>
🐛current Поведение (ошибка):
Когда я загружаю файл (видео, изображение или подзаголовок), он мгновенно показывает, что предварительно выключает в таблице. исчезает, но URL -файл все еще находится в состоянии (uploaddetails).
Если я снова нажимаю на загрузку, форма все еще содержит правильный URL -адрес файла - это просто предварительный просмотр, который исчезает. Предоставляя все мои межсековые файлы, поэтому, пожалуйста, помогите мне исправить это
Проблема в видео :: gdrive
Полный код: код
Strong>showupload.jsx
Strong>showupload.jsx>
import { useEffect, useState } from "react";
import { Separator } from "@/components/ui/separator";
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { ShowBasicDetails } from "./tabs/ShowBasicDetails";
import { ShowFileUpload } from "./tabs/showFileUpload";
import { ScrollArea } from "../../ui/scroll-area";
import { Button } from "../../ui/button";
import { toast } from "react-hot-toast";
import {
FINAL_initialState,
FINAL_showVideoInitialFormData,
} from "../../../config/formFields";

export const ShowUpload = () => {
const [activeTab, setActiveTab] = useState("showDetails");
const [showDetailsData, setShowDetailsData] = useState(FINAL_initialState);
const [UploadDetailsData, setUploadDetailsData] = useState({});
const [category, setCategory] = useState("");

useEffect(() => {
setCategory(showDetailsData.category);
}, [showDetailsData.category]);

const handleNext = () => {
if (activeTab === "showDetails") {
// if (!category) {
// toast.error("Please select a category first.");
// return;
// }
setActiveTab("showUpload");
}
};

const handlePrevious = () => {
if (activeTab === "showUpload") {
setActiveTab("showDetails");
}
};

const handleCancel = () => {
toast.success("Upload Cancelled.");
setShowDetailsData(FINAL_initialState);
setUploadDetailsData({});
};

const handleUpload = () => {
const payload = {
...showDetailsData,
...UploadDetailsData,
};
console.log("FINAL DATA TO BACKEND: ✅🔥", payload);
toast.success("Show Uploaded Successfully! 🎉");
};

return (

{/* ✅ Tabs */}

setActiveTab(val)}
className="w-[400px]"
>

Show Details
Show Upload






{activeTab === "showDetails" && (

)}
{activeTab === "showUpload" && (

)}


{activeTab === "showDetails" && (


Cancel


Next


)}
{activeTab === "showUpload" && (


Previous

Upload

)}


);
};


showbasicdetails.jsx
/* eslint-disable react/prop-types */
import { FINAL_showBasicFormControls } from "../../../../config/formFields";
import { AdminForm } from "../../../common/common-Form/adminForm";

export const ShowBasicDetails = ({ showDetails, setShowDetails }) => {
return (

Details


);
};


showfileupload.jsx
import { useEffect, useState } from "react";
import { Button } from "../../../ui/button";
import { Label } from "../../../ui/label";
import { Input } from "../../../ui/input";
import { X } from "lucide-react";
import { toast } from "react-hot-toast";
import { AdminFileUpload } from "../../../common/common-Form/adminFileUpload";

export const ShowFileUpload = ({
category,
UploadDetails,
setUploadDetails,
}) => {
const [episodes, setEpisodes] = useState([
{ title: "", video: null, subtitle: null },
]);
const [movie, setMovie] = useState({
video: null,
subtitle: null,
});

// ✅ Reset Data When Category Changes 🔥
useEffect(() => {
if (category === "movie") {
setMovie({ video: null, subtitle: null });
setUploadDetails({ movie: { video: null, subtitle: null } });
} else {
setEpisodes([{ title: "", video: null, subtitle: null }]);
setUploadDetails({
episodes: [{ title: "", video: null, subtitle: null }],
});
}
}, [category]);

// ✅ Sync Movie Data With Parent 🔥
useEffect(() => {
if (category === "movie") {
setUploadDetails({ movie });
}
}, [movie]);

// ✅ Sync Episode Data With Parent 🔥
useEffect(() => {
if (category === "webseries") {
setUploadDetails({ episodes });
}
}, [episodes]);

// ✅ Handle Add Episode 🔥
const handleAddEpisode = () => {
setEpisodes([...episodes, { title: "", video: null, subtitle: null }]);
};

// ✅ Handle Remove Episode 🔥
const handleRemoveEpisode = (index) => {
if (episodes.length === 1) {
toast.error("At least one episode is mandatory.");
return;
}
const updatedEpisodes = episodes.filter((_, i) => i !== index);
setEpisodes(updatedEpisodes);
};

// ✅ Handle File & Text Change 🔥
const handleChange = (index, field, value) => {
const updatedEpisodes = [...episodes];
updatedEpisodes[index][field] = value;
setEpisodes(updatedEpisodes);
};

// ✅ Handle Video Removal 🔥
const handleRemoveVideo = (index) => {
const updatedEpisodes = [...episodes];
updatedEpisodes[index].video = null;
setEpisodes(updatedEpisodes);
};

if (!category) {
return "Choose Category";
}

return (


{category === "movie" ? "Upload Movie & Subtitle" : "Upload Episodes"}


{/* ✅ IF CATEGORY IS MOVIE */}
{category === "movie" ? (

Upload Movie
setMovie((prev) => ({ ...prev, video: file }))}
/>

Upload Subtitle

setMovie((prev) => ({ ...prev, subtitle: file }))
}
/>

) : (


+ Add Episode

{/* ✅ LOOP THROUGH EPISODES */}
{episodes.map((episode, index) => (
key={index}
className="p-4 border rounded-md bg-gray-800 mb-4 relative"
>
{/* ✅ REMOVE BUTTON AT TOP RIGHT */}

{index > 0 && (
handleRemoveEpisode(index)}
>
Remove

)}

{/* ✅ EPISODE TITLE */}
Episode {index + 1}
handleChange(index, "title", e.target.value)}
placeholder={`Episode ${index + 1} Title`}
/>

{/* ✅ VIDEO UPLOAD */}
Upload Video
handleChange(index, "video", file)}
/>

{/* ✅ VIDEO PREVIEW */}
{episode.video && episode.video instanceof File && (

handleRemoveVideo(index)}
>



)}

{/* ✅ SUBTITLE UPLOAD */}
Upload Subtitle
handleChange(index, "subtitle", file)}
/>

))}

)}

);
};


adminfileupload.jsx
/* eslint-disable react/prop-types */
import { FileIcon, UploadCloudIcon, XIcon } from "lucide-react";
import { Input } from "../../ui/input";
import { useRef, useState } from "react";
import { toast } from "react-hot-toast";

export const AdminFileUpload = ({
onUpload = () => {}, // ✅ It will directly pass fileUrl to FormData
accept = "image/*,video/*,.srt,.vtt",
text = "Upload File",
}) => {
const [file, setFile] = useState(null);
const inputRef = useRef(null);

// ✅ Handle File Upload Click
function handleClick() {
if (inputRef.current) inputRef.current.click();
}

// ✅ Handle File Selection
function handleFileChange(event) {
const selectedFile = event.target.files[0];
if (!selectedFile) {
toast.error("❌ File Upload Failed!");
return;
}

// ✅ Reset Input Lock
event.target.value = "";

// ✅ Generate File URL
const fileUrl = URL.createObjectURL(selectedFile);

// ✅ Save File State
setFile({
name: selectedFile.name,
url: fileUrl,
type: selectedFile.type,
size: selectedFile.size,
raw: selectedFile,
});

// ✅ Pass File URL Directly to FormData
onUpload(fileUrl);

// ✅ Show Confirmation Based on File Type
if (selectedFile.type.startsWith("video/")) {
toast.success("✅ Video File Selected!");
} else if (
selectedFile.name.endsWith(".srt") ||
selectedFile.name.endsWith(".vtt")
) {
toast.success("✅ Subtitle File Selected!");
} else {
toast.success(`✅ ${selectedFile.name} Uploaded Successfully!`);
}
}

// ✅ Handle File Removal
function handleRemoveFile(event) {
event.stopPropagation();
setFile(null);
onUpload(""); // ✅ Pass Empty URL to FormData
toast.success("File Removed Successfully!");
}

return (

{/* ✅ UPLOAD BOX */}



{/* ✅ FILE PREVIEW INSIDE BOX */}
{file ? (

{/* ✅ REMOVE BUTTON INSIDE THE BOX */}



{/* ✅ IF IMAGE */}
{file.type.startsWith("image/") && (
[img]{file.url}
className="w-full h-[150px] object-none rounded-lg "
/>
)}

{/* ✅ IF VIDEO */}
{file.type.startsWith("video/") && (

)}

{/* ✅ IF SUBTITLE */}
{(file.name.endsWith(".srt") || file.name.endsWith(".vtt")) && (



{file.name}


)}

) : (

{/* ✅ DEFAULT UPLOAD AREA */}

Click to select {text}

)}


);
};


adminform.jsx
/* eslint-disable no-undef */
/* eslint-disable react-refresh/only-export-components */
/* eslint-disable react/prop-types */

import { Input } from "../../ui/input";
import { Label } from "../../ui/label";
import { Button } from "../../ui/button";
import { Textarea } from "../../ui/textarea";
import { ToggleGroup, ToggleGroupItem } from "../../ui/toggle-group";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "../../ui/select";
import { Popover, PopoverContent, PopoverTrigger } from "../../ui/popover";
import { Calendar } from "../../ui/calendar";
import { AdminFileUpload } from "./adminFileUpload";

export const AdminForm = ({ formControls = [], formData, setFormData }) => {
// Function to render inputs dynamically based on component type
function renderInputsByComponentType(getControlItem) {
let element = null;
const value = formData[getControlItem.name] || "";

switch (getControlItem.componentType) {
// Input Field
case "input":
element = (

setFormData({
...formData,
[getControlItem.name]: event.target.value,
})
}
/>
);
break;

// Select Dropdown
case "select":
element = (

setFormData({ ...formData, [getControlItem.name]: value })
}
value={value}
>




{getControlItem.options &&
getControlItem.options.map((optionItem) => (

{optionItem.label}

))}


);
break;

case "textarea":
element = (

setFormData({
...formData,
[getControlItem.name]: event.target.value,
})
}
/>
);
break;
// Toggle Group (Genre Selection)

case "toggle-group":
element = (

{getControlItem.options.map((optionItem) => (

{optionItem.label}

))}

);
break;

// Date Picker (Better Date Format)
case "date":
element = (



{formData[getControlItem.name]
? new Date(formData[getControlItem.name]).toLocaleDateString()
: "Pick a date"}



{
if (selectedDate) {
setFormData({
...formData,
[getControlItem.name]: selectedDate
.toISOString()
.split("T")[0], // Saves as YYYY-MM-DD
});
}
}}
initialFocus
/>


);
break;

// File Upload (Dynamic Accept Type)
case "file":
element = (

setFormData({
...formData,
[getControlItem.name]: fileUrl,
})
}
/>
);
break;

default:
element = (

setFormData({
...formData,
[getControlItem.name]: event.target.value,
})
}
/>
);
break;
}
return element;
}

return (

{formControls.map((controleItem) => (

{controleItem.label}
{renderInputsByComponentType(controleItem)}

))}

);
};



Подробнее здесь: https://stackoverflow.com/questions/794 ... e-persists
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Javascript»