React组件中require加载图片路径失败问题求助
问题描述
在React组件RecipeComp中,通过接口获取的data.type和data.url能在第2、3行的<p>标签正常渲染,但在第1行通过require拼接路径传入RecipeProfileImg组件时失败,控制台报错Cannot find module './undefined/undefined'。尝试用模板字符串../../Assets/Images/${data.type}/${data.url}写法后问题依旧,已确认路径本身正确,请问问题原因是什么?
组件代码
import { useState, useEffect } from "react"; import { useParams } from "react-router-dom"; import RecipeService from "./RecipeService"; import RecipeProfileImg from "./RecipeProfileImg"; import "../../Assets/css/recipePage.css"; const RecipeComp = () => { const {id} = useParams(); const [data, setData] = useState({}); /*const [data, setData] = useState({ name: 'name1', type: 'tipo1', url: 'path1', ingredients: 'ingr1', method: 'meth1', preparationTime: 10, cookingTime: 10 });*/ useEffect(() => { RecipeService.readRecipeById(id).then((res) => { console.log(res.data.type); setData(res.data); }); }, [id]); function splitIngredients(ingrs){ const pieces = ingrs.split(", "); const listItems = []; for(let i = 0; i < pieces.length; i++){ const elem = <li>{pieces[i]}</li>; listItems.push(elem); } return listItems; } return( <div> <h1>{data.name}</h1> <RecipeProfileImg imgSrc={require("../../Assets/Images/" + data.type + "/" + data.url)} /> <p id={data.url}>{data.type}</p> <p id={data.type}>{data.url}</p> <div className="listsBox"> <label className="listLab">Ingredienti: <ul className="listx"> { splitIngredients(data.ingredients) } </ul> </label> <label className="listLab">Tempi: <ul className="listx"> <li>Tempo di Preparazione: {data.preparationTime} min</li> <li>Tempo di Cottura: {data.cookingTime} min</li> </ul> </label> </div> <h3 className="prepTitle">Preparazione</h3> <p className="methodPar">{data.method}</p> <a href={'/recipes/delete/' + id}>delete me</a> <br /> <a href={'/recipes/update/' + id}>update me</a> </div> ); } export default RecipeComp;
问题代码行
1) <RecipeProfileImg imgSrc={require("../../Assets/Images/" + data.type + "/" + data.url)} /> 2) <p id={data.url}>{data.type}</p> 3) <p id={data.type}>{data.url}</p>
原因分析及解决方案
核心原因
require是Webpack等打包工具在编译阶段执行的静态资源加载方法,它无法识别运行时动态生成的路径。
组件初始化时,data的初始值是空对象{},此时data.type和data.url都是undefined,第一次渲染时会执行require("../../Assets/Images/undefined/undefined"),直接触发找不到模块的错误——即便后续接口返回数据更新了data,也无法修复这次编译阶段的错误。
而<p>标签里的{data.type}和{data.url}是运行时的插值渲染,初始时显示空或undefined,等接口数据返回后会自动更新,所以不会报错。
解决方案
方案1:条件渲染,确保数据存在后再加载图片
在require外层加判断,只有当data.type和data.url都存在时才执行加载:
<RecipeProfileImg imgSrc={data.type && data.url ? require(`../../Assets/Images/${data.type}/${data.url}`) : null} />
同时在RecipeProfileImg组件里处理imgSrc为null的情况(比如显示占位图)。
方案2:改用ES模块动态导入(推荐)
使用import()动态导入图片,这是运行时加载方式,适配动态路径场景:
// 新增状态存储图片地址 const [imgSrc, setImgSrc] = useState(null); useEffect(() => { if (data.type && data.url) { import(`../../Assets/Images/${data.type}/${data.url}`) .then(imgModule => setImgSrc(imgModule.default)) .catch(err => console.error("图片加载失败", err)); } }, [data.type, data.url]);
渲染时直接使用状态里的图片地址:
<RecipeProfileImg imgSrc={imgSrc} />
方案3:将图片放在public目录,使用绝对路径
如果把图片放在项目的public文件夹下,可直接用字符串拼接路径,无需require:
<RecipeProfileImg imgSrc={data.type && data.url ? `/Assets/Images/${data.type}/${data.url}` : null} />
注意:这种方式下Webpack不会对图片进行打包优化,需根据项目需求选择。
内容的提问来源于Stack Exchange,提问作者Andrea Zak

