React组件useState初始值为null时出现读取undefined属性报错求助
React项目中useState初始值为null导致的解构与API请求报错解决
问题描述
我正在借助Rapid API的Youtube V3 API制作YouTube克隆项目,用axios封装了fetchFromApi方法获取数据。当给useState Hook设置初始值为null时,出现两个核心报错:
Cannot read properties of undefined (reading '0'):API请求返回结果时直接访问data.items[0],但data.items可能为空或未定义- 解构
videoDetail时无法读取snippet/statistics属性:组件首次渲染时videoDetail为null,直接解构会触发类型错误
相关代码:
import React, { useEffect, useState } from 'react' import { Link, useParams } from 'react-router-dom' import ReactPlayer from 'react-player' import { Typography, Box, Stack } from '@mui/material' import { CheckCircle } from '@mui/icons-material' import { Videos } from './' import { fetchFromApi } from '../utils/fetchFromApi' const VideoDetail = ({ channelDetail }) => { const { id } = useParams(); const [videoDetail, setVideoDetail] = useState(null); useEffect(() => { fetchFromApi(`videos?part=snippet,statistics&id=${id}`) .then((data) => setVideoDetail(data.items[0])); }, [id]) const { snippet: { title, channelId, channelTitle } , statistics: { viewCount, likeCount } } = videoDetail; return ( <Box minHeight='95vh'> <Stack direction={{ xs: 'column', md: 'row' }} > <Box flex={1}> <Box sx={{ width: '100%', position: 'sticky', top: '86px' }}> <ReactPlayer url={`https://www.youtube.com/watch?v=${id}`} controls className='react-player' /> <Typography color='#fff' variant='h5' fontWeight='bold' p={2}> {title} </Typography> <Stack direction='row' justifyContent='space-between' py={1} px={2} sx={{ color: '#fff' }}> </Stack> </Box> </Box> </Stack> </Box> ) } export default VideoDetail
解决方案
1. 修复API请求中的data.items[0]报错
在设置videoDetail之前,先判断data.items是否存在且包含元素,避免直接访问索引导致的未定义错误,同时添加错误捕获:
useEffect(() => { fetchFromApi(`videos?part=snippet,statistics&id=${id}`) .then((data) => { // 安全访问data.items,确保存在且有数据 if (data?.items?.length > 0) { setVideoDetail(data.items[0]); } else { // 无数据时重置状态,可根据需求添加提示 setVideoDetail(null); } }) .catch(err => { // 捕获请求异常,防止页面崩溃 console.error('视频详情获取失败:', err); setVideoDetail(null); }); }, [id])
2. 修复解构videoDetail时的类型错误
由于组件首次渲染时videoDetail为null,直接解构会报错,可通过两种方式解决:
方式一:使用可选链+默认值
给解构添加默认空对象,确保即使videoDetail为null也不会报错:
const { snippet: { title = '', channelId = '', channelTitle = '' } = {}, statistics: { viewCount = 0, likeCount = 0 } = {} } = videoDetail || {};
方式二:添加条件渲染
在videoDetail存在时再渲染相关内容,同时添加加载状态:
return ( <Box minHeight='95vh'> {videoDetail ? ( <Stack direction={{ xs: 'column', md: 'row' }} > <Box flex={1}> <Box sx={{ width: '100%', position: 'sticky', top: '86px' }}> <ReactPlayer url={`https://www.youtube.com/watch?v=${id}`} controls className='react-player' /> <Typography color='#fff' variant='h5' fontWeight='bold' p={2}> {title} </Typography> <Stack direction='row' justifyContent='space-between' py={1} px={2} sx={{ color: '#fff' }}> <Typography> {channelTitle} <CheckCircle sx={{ fontSize: 12, color: 'gray', ml: 0.5 }} /> </Typography> <Stack direction='row' gap='20px'> <Typography>{parseInt(viewCount).toLocaleString()} 次观看</Typography> <Typography>{parseInt(likeCount).toLocaleString()} 个赞</Typography> </Stack> </Stack> </Box> </Box> </Stack> ) : ( // 加载状态提示 <Box display='flex' justifyContent='center' alignItems='center' height='80vh'> <Typography color='#fff' variant='h6'>加载中...</Typography> </Box> )} </Box> )
内容的提问来源于stack exchange,提问作者Arpan Vijay
相关产品推荐
相关产品推荐

