ReactJS如何将本地JSON动态导入图片与API动态获取数据匹配
问题原因
你当前在RaceCard组件内对完整的images数组做了全量遍历渲染,所以每张卡片都会展示所有本地图片,只需要根据当前卡片对应的种族标识,匹配到对应slug的单张图片即可。
解决方案
DnD5e 开放API返回的种族数据中默认带有index字段,取值和你imagedata.json里的slug完全一致,我们可以用这个字段做匹配关联,两种实现方式可选:
方案1:直接在卡片组件内匹配(改动最小)
修改RaceCard组件代码,先匹配对应图片再渲染,不要遍历全部图片:
import React from 'react'; import Markdown from 'markdown-to-jsx'; import * as C from './styles'; import images from '../../imagedata.json'; const RaceCard = ({ data }) => { // 匹配当前种族对应的图片 const currentImage = images.find(img => img.slug === data.index); return ( <C.Container> <C.Card id={data.name} > <C.Content> <C.Title> {data.name} </C.Title> <C.Text> <Markdown>{data.desc}</Markdown> </C.Text> <C.Button> Read More </C.Button> </C.Content> {/* 只渲染匹配到的单张图片,匹配失败可显示占位图 */} {currentImage ? ( <C.Image key={currentImage.id} imgsrc={currentImage.imgsrc} slug={currentImage.slug} > <img src={currentImage.imgsrc} alt={data.name} /> </C.Image> ) : ( // 可替换为你自己的占位图 <div>暂无图片</div> )} </C.Card> </C.Container> ); }; export default RaceCard;
如果你的API返回数据没有index字段,可以把匹配条件替换为处理后的name:img => img.slug === data.name.toLowerCase().replace(/\s+/g, '-')
方案2:父组件预关联数据(性能更优)
如果卡片数量较多,在父组件提前把图片和种族数据做关联,避免每个卡片都重复遍历图片数组:
首先修改Races组件:
import React, { useEffect, useState, useMemo } from 'react'; import * as C from './styles'; import api from '../../helpers/dnd5eAPI'; import images from '../../imagedata.json'; import { Theme } from '../../components/Theme'; import RaceCard from '../../components/RaceCard'; export const Races = () => { const [races, setRaces] = useState([]); // 预生成slug到图片路径的映射表 const imageMap = useMemo(() => { return images.reduce((map, img) => { map[img.slug] = img; return map; }, {}); }, []); useEffect(() => { const getRaces = async () => { const race = await api.getRaces(); // 给每个种族数据附加对应图片信息 const racesWithImg = race.results.map(item => ({ ...item, image: imageMap[item.index] || null })); setRaces(racesWithImg); }; getRaces(); }, [imageMap]); return ( <Theme> <C.Container> {races.map((item, index) => ( <RaceCard key={index} data={item} /> ))} </C.Container> </Theme> ); };
之后在RaceCard组件里直接使用附加的image字段即可:
// RaceCard组件内无需再导入images数组 const RaceCard = ({ data }) => { return ( {/* 其他代码不变 */} {data.image && ( <C.Image imgsrc={data.image.imgsrc} slug={data.image.slug} > <img src={data.image.imgsrc} alt={data.name} /> </C.Image> )} ) }
内容的提问来源于stack exchange,提问作者BraulioPortela
相关产品推荐
相关产品推荐

