React中Tiles组件向Info组件传data.json时props为undefined的问题
问题分析与解决方案
核心问题
你遇到的undefined问题根源在于渲染逻辑冲突:
- Home组件通过
myBool控制显示<Tiles/>或<Info/>,而Tiles组件内部又自己渲染<Info/>,两个Info是完全独立的实例。 - 点击图片时,同时触发了两个事件:
img的onToggleInfo(尝试在Tiles内显示Info)和父div的onClick(调用toggleBool()让Home切换到自己的Info)。最终Home渲染的Info没有接收任何props,所以props.dataToInfo为undefined。 - 另外,你试图传递整个
data数组给Info,但Info组件期望的是单个item对象,逻辑不匹配。
解决方案一:由Home统一管理状态(推荐)
将选中的item状态提升到Home组件,统一控制Tiles和Info的显示与数据传递:
1. 修正Home.js
import React, { useState } from "react"; import Footer from "./Footer"; import Info from "./Info"; import Navbar from "./Navbar"; import Tiles from "./Tiles"; const Home = () => { const [selectedItem, setSelectedItem] = useState(null); // 切换回Tiles视图 const backToTiles = () => setSelectedItem(null); return ( <div className="m-5"> <Navbar /> {selectedItem ? ( <Info dataToInfo={selectedItem} backToTiles={backToTiles} /> ) : ( <Tiles onItemSelect={setSelectedItem} /> )} <Footer /> </div> ); }; export default Home;
2. 修正Tiles.js
移除内部的toggleInfo和sendData状态,点击图片时直接把选中的item传递给Home:
import React from "react"; import data from "../data/data"; import Player from "./Player"; const Tiles = (props) => { return ( <> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-3 mt-5"> {data && data .slice(0) .reverse() .map((item) => { return ( <div key={item.id}> <img alt={item.title} src={`${item.cover}`} className="h-50 w-35 hover:opacity-25" title={item.title} onClick={() => props.onItemSelect(item)} /> </div> ); })} </div> <Player url={data} /> </> ); }; export default Tiles;
3. 修正Info.js
直接使用传递过来的单个item对象:
import React from "react"; const Info = (props) => { const { dataToInfo, backToTiles } = props; if (!dataToInfo) return null; // 防止未选中时渲染出错 return ( <div key={dataToInfo.id}> <p onClick={backToTiles}>GO BACK</p> <p>{dataToInfo.title}</p> <p>{dataToInfo.info}</p> </div> ); }; export default Info;
解决方案二:Tiles内部独立处理Info显示
如果不需要Home参与,可让Tiles自己管理选中的item和Info的显示:
修正后的Tiles.js
import React, { useState } from "react"; import data from "../data/data"; import Info from "./Info"; import Player from "./Player"; const Tiles = () => { const [selectedItem, setSelectedItem] = useState(null); const backToTiles = () => setSelectedItem(null); return ( <> {selectedItem ? ( <Info dataToInfo={selectedItem} backToTiles={backToTiles} /> ) : ( <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-3 mt-5"> {data && data .slice(0) .reverse() .map((item) => { return ( <div key={item.id}> <img alt={item.title} src={`${item.cover}`} className="h-50 w-35 hover:opacity-25" title={item.title} onClick={() => setSelectedItem(item)} /> </div> ); })} </div> )} <Player url={data} /> </> ); }; export default Tiles;
对应的Home.js(简化)
import React from "react"; import Footer from "./Footer"; import Navbar from "./Navbar"; import Tiles from "./Tiles"; const Home = () => { return ( <div className="m-5"> <Navbar /> <Tiles /> <Footer /> </div> ); }; export default Home;
Info.js与方案一保持一致即可。
额外注意点
- 移除了重复的点击事件:之前父
div和img的onClick会冲突,现在只保留img的点击事件来触发选中逻辑。 - 避免了
setState异步问题:不再依赖setSendData后的即时读取,直接传递选中的item,状态更新更可靠。 - 增加了空值判断:Info组件里判断
dataToInfo是否存在,防止渲染出错。
内容的提问来源于stack exchange,提问作者edo
相关产品推荐
相关产品推荐

