React Hooks/Context编译渲染报错:无法读取videos属性
问题原因分析
这个错误的核心是异步数据加载的渲染时机问题:
- 组件初始化时,
text的状态是{}空对象;useEffect中的fetch是异步操作,第一次渲染时还没完成数据请求,无法拿到JSON内容。 - 此时
text[language](比如默认的text['ES'])返回undefined,继续访问.videos就会触发Cannot read properties of undefined (reading 'videos')错误。 - 编译后修改代码触发热重载时,JSON数据已经被缓存,组件能直接拿到数据,所以不会报错。
解决方案
方案1:初始化默认语言数据
在useState里给text设置与JSON结构匹配的初始值,确保第一次渲染时有可用数据:
const [text, setText] = useState({ ES: { videos: "Vídeos", photos: "Fotos", cv: "CV", press: "Prensa", contact: "Contacto" }, EU: { videos: "Bideoak", photos: "Argazkiak", cv: "CV", press: "Prentsa", contact: "Kontaktua" }, EN: { videos: "Videos", photos: "Photos", cv: "CV", press: "Press", contact: "Contact" } });
方案2:使用可选链做空值保护
在访问嵌套属性前,用可选链操作符?.判断上层属性是否存在,避免报错:
<li><Link to="/videos" className="nav-item">{text[language]?.videos}</Link></li> <li><Link to="/photos" className="nav-item">{text[language]?.photos}</Link></li> <li><Link to="/cv" className="nav-item">{text[language]?.cv}</Link></li> <li><Link to="/press" className="nav-item">{text[language]?.press}</Link></li> <li><Link to="/contact" className="nav-item">{text[language]?.contact}</Link></li>
也可以加上加载提示:
<li><Link to="/videos" className="nav-item">{text[language]?.videos || '加载中...'}</Link></li>
方案3:添加加载状态控制渲染
在Context中新增加载状态,确保数据加载完成后再渲染子组件:
修改LanguageContext.js:
import { createContext, useContext, useState, useEffect } from "react"; const LanguageContext = createContext(undefined) export const LanguageProvider = ({ children }) => { const [language, setLanguage] = useState('ES'); const [text, setText] = useState({}); const [isLoading, setIsLoading] = useState(true); // 新增加载状态 const updateLanguage = e => setLanguage(e.target.value) useEffect(() => { fetch(`https://raw.githubusercontent.com/julenclarke/ejtos-react_budget_app/main/languagesdata.json`) .then((response) => response.json()) .then((jsonData) => { setText(jsonData); setIsLoading(false); }) .catch((error) => { console.log(error); setIsLoading(false); }); }, []); return ( <LanguageContext.Provider value={{ language, updateLanguage, text }} > {isLoading ? <div>加载中...</div> : children} </LanguageContext.Provider> ) } export const useLanguage = () => useContext(LanguageContext);
内容的提问来源于stack exchange,提问作者Julen Clarke
相关产品推荐
相关产品推荐

