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

React中如何追踪并保存视频文件与标题的配对及更新

React中追踪视频文件与标题配对并实现保存/更新

核心问题修正

首先你的代码存在一个明显的结构错误:handleChange和handleSubmit被定义在handleVideoChange函数内部,这会导致每次选择视频时都重新创建这两个函数,既浪费性能也可能引发异常渲染。先把这两个函数移到外部作用域。

关于视频-标题配对的追踪,你想用字典(对象)存储的思路是可行的,但要注意:如果允许相同标题的视频,直接用标题做键会覆盖旧数据;如果强制标题唯一,可直接用标题作为键。下面给出两种实用实现方案。


方案1:标题作为唯一键(字典模式)

适合确保标题不重复的场景,用对象存储键值对。

1. 修正状态初始化

const [videoTitle, setVideoTitle] = useState("");
const [videosrc, setVideosrc] = useState("");
const [isUploaded, setIsUploaded] = useState(false);
const [isDone, setIsDone] = useState(false);
const [fileName, setFileName] = useState("");
const [currentFile, setCurrentFile] = useState(null); // 新增:存储当前选中的File对象
const [allFiles, setAllFiles] = useState({}); // 修正原拼写错误setAtllFiles,初始化为空对象

2. 修正事件函数结构

const handleVideoChange = (event) => {
  try {
    const file = event.target.files[0];
    if (!file) return; // 处理未选择文件的情况

    setIsUploaded(true);
    setVideosrc(URL.createObjectURL(file));
    setFileName(file.name);
    setCurrentFile(file); // 保存当前File对象到状态
  } catch (error) {
    console.log(error);
  }
};

const handleChange = (e) => {
  setVideoTitle(e.target.value);
};

const handleSubmit = (e) => {
  e.preventDefault();
  if (!videoTitle || !currentFile) return; // 校验必填项

  // 保存配对:以标题为键,存储文件、预览地址等信息
  setAllFiles(prev => ({
    ...prev,
    [videoTitle]: {
      file: currentFile,
      src: videosrc,
      fileName: fileName
    }
  }));

  // 清空当前输入状态
  setVideoTitle("");
  setVideosrc("");
  setFileName("");
  setCurrentFile(null);
  setIsUploaded(false);
  setIsDone(true);

  // 同步给父组件(如果需要)
  props.onSubmit({
    id: Math.floor(Math.random() * 10000),
    title: videoTitle,
    src: videosrc,
    fileName: fileName
  });
};

方案2:支持重复标题(数组模式,更灵活)

适合允许相同标题的场景,用数组存储每个配对对象,每个对象带唯一ID用于后续修改/删除。

1. 状态初始化

const [videoTitle, setVideoTitle] = useState("");
const [videosrc, setVideosrc] = useState("");
const [isUploaded, setIsUploaded] = useState(false);
const [isDone, setIsDone] = useState(false);
const [fileName, setFileName] = useState("");
const [currentFile, setCurrentFile] = useState(null);
const [allFiles, setAllFiles] = useState([]); // 初始化为空数组
const [editingItem, setEditingItem] = useState(null); // 新增:标记当前编辑的配对

2. 核心逻辑实现

// 进入编辑模式的函数(比如点击列表中的某一项触发)
const startEditing = (item) => {
  setEditingItem(item);
  setVideoTitle(item.title);
  setVideosrc(item.src);
  setFileName(item.fileName);
  setCurrentFile(item.file);
  setIsUploaded(true);
};

const handleVideoChange = (event) => {
  try {
    const file = event.target.files[0];
    if (!file) return;

    setIsUploaded(true);
    setVideosrc(URL.createObjectURL(file));
    setFileName(file.name);
    setCurrentFile(file);
  } catch (error) {
    console.log(error);
  }
};

const handleChange = (e) => {
  setVideoTitle(e.target.value);
};

const handleSubmit = (e) => {
  e.preventDefault();
  if (!videoTitle || !currentFile) return;

  if (editingItem) {
    // 编辑模式:更新数组中对应的条目
    setAllFiles(prev => prev.map(item => 
      item.id === editingItem.id 
        ? {...item, title: videoTitle, file: currentFile, src: videosrc, fileName: fileName} 
        : item
    ));
    setEditingItem(null);
  } else {
    // 新增模式:添加新配对到数组
    const newVideoPair = {
      id: Math.floor(Math.random() * 10000), // 生成唯一ID
      title: videoTitle,
      file: currentFile,
      src: videosrc,
      fileName: fileName
    };
    setAllFiles(prev => [...prev, newVideoPair]);
    props.onSubmit(newVideoPair);
  }

  // 清空输入状态
  setVideoTitle("");
  setVideosrc("");
  setFileName("");
  setCurrentFile(null);
  setIsUploaded(false);
  setIsDone(true);
};

关键注意事项

  • 存储File对象到React状态是可行的,但组件卸载时需要释放预览地址避免内存泄漏,可通过useEffect处理:
useEffect(() => {
  return () => {
    if (videosrc) {
      URL.revokeObjectURL(videosrc);
    }
  };
}, [videosrc]);
  • 除非能确保标题绝对唯一,否则不推荐用标题作为字典键,数组模式的扩展性更强,支持后续的修改、删除操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 18:33:10