React中页面间传递videoUrl跳转后视频无法显示的问题求助
React路由传递视频URL后视频无法播放的解决方法
问题描述
点击表格内的“Watch Video”链接时,将videoUrl传递到VideoFeedback页面,但跳转后视频无法正常显示。直接在浏览器粘贴从数据库获取的该视频URL可以正常播放,使用了React-Router-DOM的Link组件和useParams钩子实现跳转传参。
相关代码
ListVideos页面代码
import React, { useState, useEffect } from 'react'; import { Link } from 'react-router-dom'; import { Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper } from '@mui/material'; import axios from 'axios'; const ListVideos = () => { const [videos, setVideos] = useState([]); const [distinctAssignments, setDistinctAssignments] = useState([]); const [selectedAssignment, setSelectedAssignment] = useState(''); const [visibleCount, setVisibleCount] = useState(3); const [showMore, setShowMore] = useState(false); const [error, setError] = useState(''); // Fetch videos from the API useEffect(() => { const fetchVideos = async () => { try { const response = await axios.get('http://localhost:5000/video-submissions'); setVideos(response.data); // Extract distinct assignment names after fetching videos const uniqueAssignments = [...new Set(response.data.map(video => video.assign_name))]; setDistinctAssignments(uniqueAssignments); } catch (error) { console.error('Error fetching videos:', error); setError('Failed to load videos. Please try again later.'); } }; fetchVideos(); }, []); const toggleShowMore = () => { setShowMore(!showMore); setVisibleCount(showMore ? 3 : videos.length); }; // Filter videos by selected assignment name const filteredVideos = videos.filter(video => selectedAssignment ? video.assign_name === selectedAssignment : true ); return ( <div className="page"> <header> <div className="container"> <h1 className="page-heading">List of Video Submissions</h1> <ul className="linksList"> <li> <Link to="/" className="link">Landing Page</Link> </li> <li> <Link to="/watch-feedback/:id" className="link">Watch Video</Link> </li> </ul> </div> </header> <div className="page-Container"> <div className="assignment-container"> <label htmlFor="assignment">Filter by Assignment Name:</label> <select value={selectedAssignment} onChange={(e) => setSelectedAssignment(e.target.value)} aria-label="Select Assignment" style={{ marginBottom: '10px', padding: '8px', width: '100%' }} > <option value="">Select an assignment...</option> {distinctAssignments.length > 0 ? ( distinctAssignments.map((assignment, index) => ( <option key={index} value={assignment}> {assignment} </option> )) ) : ( <option disabled>No assignments available</option> )} </select> </div> {error && <div className="error-message">{error}</div>} <TableContainer component={Paper} className="fixed-table-container"> <Table stickyHeader> <TableHead> <TableRow> <TableCell><strong>Assignment Name</strong></TableCell> <TableCell><strong>Submitted By (User ID)</strong></TableCell> <TableCell><strong>Time Submitted</strong></TableCell> <TableCell><strong>Assignment ID</strong></TableCell> <TableCell><strong>Video URL</strong></TableCell> </TableRow> </TableHead> <TableBody> {filteredVideos.slice(0, visibleCount).map((video) => ( <TableRow key={video.videoId}> <TableCell>{video.assign_name}</TableCell> <TableCell>{video.user_id}</TableCell> <TableCell>{new Date(video.upload_date).toLocaleString()}</TableCell> <TableCell>{video.assignment_id}</TableCell> <TableCell> <Link to={`/watch-feedback/${encodeURIComponent(video.videoUrl)}`} // Use encodeURIComponent for safety onClick={() => console.log(video.videoUrl)} // Log the video URL for debugging > Watch Video </Link> </TableCell> </TableRow> ))} </TableBody> </Table> </TableContainer> <button className="get-started-button" onClick={toggleShowMore}> {showMore ? 'Show Less' : 'Show More'} </button> </div> </div> ); }; export default ListVideos;
VideoFeedback页面代码
import React, { useState } from 'react'; import { Link, useParams } from 'react-router-dom'; import axios from 'axios'; const VideoFeedback = () => { const { videoUrl } = useParams(); // Get videoUrl from URL parameters const [mark, setMark] = useState(''); const [comment, setComment] = useState(''); const handleSubmitFeedback = async (e) => { e.preventDefault(); try { const response = await axios.post('/api/marks/submit-feedback', { videoUrl, // Use videoUrl directly here mark, comment, }); alert(response.data.message); } catch (error) { console.error('Error submitting feedback:', error); alert('Failed to submit feedback. Please try again.'); } }; return ( <div className="page"> <header> <div className="container"> <h1 className="page-heading">Watch Video and Provide Feedback</h1> <ul className="linksList"> <li><Link to="/" className="link">Landing Page</Link></li> <li><Link to="/list-videos" className="link">Back to Video List</Link></li> </ul> </div> </header> <div className="page-Container"> {/* Video Player */} {videoUrl ? ( <video width="640" height="360" controls autoPlay> <source src={decodeURIComponent(videoUrl)} type="video/mp4" /> Your browser does not support the video tag. </video> ) : ( <p>No video available to play.</p> )} {/* Feedback Form */} <form onSubmit={handleSubmitFeedback} className="feedback-form"> <div className="form-group"> <label htmlFor="mark">Mark:</label> <input type="number" id="mark" value={mark} onChange={(e) => setMark(e.target.value)} required min="0" max="100" placeholder="Enter mark out of 100" /> </div> <div className="form-group"> <label htmlFor="comment">Commentary Feedback:</label> <textarea id="comment" value={comment} onChange={(e) => setComment(e.target.value)} required placeholder="Enter your feedback here" ></textarea> </div> <button type="submit" className="feedback-Sub">Submit Feedback</button> </form> </div> </div> ); }; export default VideoFeedback;
App.js代码
import React from 'react'; import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'; import LandingPage from './pages/LandingPage'; import LoginPage from './pages/LoginPage'; import UserAdminPage from './pages/UserAdminPage'; import ListAssignments from './pages/ListAssignments'; import CreateAssignment from './pages/CreateAssignment'; import ListVideos from './pages/ListVideos'; import VideoFeedback from './pages/VideoFeedback'; import StudentPage from './pages/studentPage'; import LecturerPage from './pages/lecturerPage'; import logo from './logo.svg'; import './App.css'; const App = () => { return ( <Router> <Routes> <Route path="/" element={<LandingPage />} /> <Route path="/login" element={<LoginPage />} /> <Route path="/user-admin" element={<UserAdminPage />} /> <Route path="/list-assignments" element={<ListAssignments />} /> <Route path="/create-assignment" element={<CreateAssignment />} /> <Route path="/list-videos" element={<ListVideos />} /> <Route path="/watch-feedback/:id" element={<VideoFeedback />} /> <Route path="/user-student" element={<StudentPage />} /> <Route path="/user-lecturer" element={<LecturerPage />} /> </Routes> </Router> ); }; export default App;
问题排查与修复
1. 路由参数名称不匹配(核心问题)
在App.js中,路由定义为/watch-feedback/:id,但在VideoFeedback组件中,你尝试获取的参数是videoUrl:
const { videoUrl } = useParams();
参数名称必须完全一致,有两种修改方式:
方式一:修改路由定义
将App.js中的路由改为:<Route path="/watch-feedback/:videoUrl" element={<VideoFeedback />} />这样组件中
useParams()获取的videoUrl就能匹配到路由参数。方式二:修改组件内参数名
在VideoFeedback组件中改为获取id参数,再解码使用:const { id } = useParams(); // 后续使用时解码:decodeURIComponent(id)
2. 验证URL编码解码的正确性
虽然你已经使用encodeURIComponent()处理了传递的URL,但建议在VideoFeedback组件中打印解码后的URL,确认是否与原URL一致:
const { videoUrl } = useParams(); const decodedUrl = decodeURIComponent(videoUrl); console.log('Decoded Video URL:', decodedUrl); // 检查控制台输出是否正确
确保解码后的URL和直接粘贴到浏览器的URL完全相同,没有字符丢失或转义错误。
3. 视频标签的额外检查
- 确认
video标签的type属性与视频格式匹配,如果视频不是mp4,需要修改type值(比如video/webm)。 - 检查是否存在跨域问题:如果视频存储在外部服务器,需要确保服务器配置了CORS允许你的前端域名访问。
修改后的关键代码示例
修改后的App.js路由
<Route path="/watch-feedback/:videoUrl" element={<VideoFeedback />} />
修改后的VideoFeedback组件(验证解码)
const VideoFeedback = () => { const { videoUrl } = useParams(); const decodedUrl = decodeURIComponent(videoUrl); console.log('Decoded URL:', decodedUrl); const [mark, setMark] = useState(''); const [comment, setComment] = useState(''); const handleSubmitFeedback = async (e) => { e.preventDefault(); try { const response = await axios.post('/api/marks/submit-feedback', { videoUrl: decodedUrl, mark, comment, }); alert(response.data.message); } catch (error) { console.error('Error submitting feedback:', error); alert('Failed to submit feedback. Please try again.'); } }; return ( <div className="page"> {/* 其余代码省略 */} <div className="page-Container"> {decodedUrl ? ( <video width="640" height="360" controls autoPlay> <source src={decodedUrl} type="video/mp4" /> Your browser does not support the video tag. </video> ) : ( <p>No video available to play.</p> )} {/* 表单代码省略 */} </div> </div> ) }
内容的提问来源于stack exchange,提问作者Charmaine Msibi
相关产品推荐
相关产品推荐

