React中如何通过Props关联Firebase存储图片与博客卡片数据?
解决React中Firebase Storage图片与实时数据库博客关联的问题
我在React项目中尝试从Firebase Storage获取图片,将其与Firebase实时数据库的博客信息结合后,通过Props传递给博客卡片组件。目前已成功获取博客信息和Storage图片,但无法通过图片文件名与博客ImageID属性一致的规则将两者关联,进而把对应图片URL传给博客组件。
获取博客信息与Firebase图片的原代码
import BlogPost from "./BlogPost"; import { useEffect, useState } from "react"; import { ref, listAll, getDownloadURL } from "firebase/storage"; import storage from "../../firebase"; interface Blog { id: string; title: string; desc: string; ImageID: string; } interface BlogImage { name: string; url: string; } const BlogsList = () => { const [blogs, setBlogs] = useState<Blog[]>([]); const [images, setImages] = useState<BlogImage[]>([]); const imagesRef = ref(storage, "banners/") useEffect(() => { listAll(imagesRef).then((response) => { response.items.forEach((item) => { getDownloadURL(item).then((url) => { setImages((prev: any) => [...prev, url]) }) }) }) }, []); useEffect(() => { const fetchBlogs = async () => { const response = await fetch("#"); const responseData = await response.json(); const loadedBlogs:Blog[] = []; for (const key in responseData) { loadedBlogs.push({ id: key, title: responseData[key].title, desc: responseData[key].desc, ImageID: responseData[key].image, }); } setBlogs(loadedBlogs); }; fetchBlogs(); }); return ( <div className="flexcontainer"> {images.map((url: any) => { return <img style={{ width: `20%` }} src={url}/> })} {blogs.map((blog) => ( <BlogPost key={blog.id} image={blog.ImageID} title={blog.title} desc={blog.desc} /> ))} </div> ); }; export default BlogsList;
接收Props的博客卡片组件代码
const BlogPost = (props: any) => { return ( <div className={`${classes.card} flex1x5 `}> <header className={classes.card__header} style={{ backgroundSize: "cover", background: `url(${props.image})`, }} ></header> <div className={classes.card__body}> <h3 className={classes.blog__name}>{props.title}</h3> <p className={classes.blog__desc}>{props.desc}</p> <button className={classes.arrow}> Read More <i className={`${classes.linkarrow} fa-sharp fa-solid fa-arrow-right`} ></i> </button> </div> </div> ); };
解决方案
1. 修正图片存储逻辑,保留文件名与URL的映射
原代码仅存储图片URL,丢失了用于匹配的文件名信息。修改图片获取逻辑,将文件名和URL的对应关系存入images状态:
useEffect(() => { listAll(imagesRef).then((response) => { // 用Promise.all批量处理,减少状态更新次数 Promise.all( response.items.map(item => getDownloadURL(item).then(url => ({ name: item.name, url })) ) ).then(imageList => { setImages(imageList); }); }) }, []);
2. 修复博客获取的useEffect依赖,避免无限渲染
原第二个useEffect无依赖项,会导致组件无限重复请求博客数据,添加空依赖数组:
useEffect(() => { const fetchBlogs = async () => { const response = await fetch("#"); const responseData = await response.json(); const loadedBlogs:Blog[] = []; for (const key in responseData) { loadedBlogs.push({ id: key, title: responseData[key].title, desc: responseData[key].desc, ImageID: responseData[key].image, }); } setBlogs(loadedBlogs); }; fetchBlogs(); }, []); // 添加空依赖数组,仅初始化时请求一次
3. 渲染时匹配对应图片URL
遍历博客列表时,通过ImageID从images数组中找到对应的图片URL,传递给BlogPost组件:
return ( <div className="flexcontainer"> {blogs.map((blog) => { // 匹配当前博客对应的图片 const matchedImage = images.find(img => img.name === blog.ImageID); return ( <BlogPost key={blog.id} image={matchedImage?.url || ""} // 匹配到则用URL,否则留空或设置默认图 title={blog.title} desc={blog.desc} /> ) })} </div> );
可选优化:等待数据加载完成后再渲染
添加加载状态,避免数据未就绪时渲染空内容:
const [isLoading, setIsLoading] = useState(true); // 并行获取图片和博客数据,减少等待时间 useEffect(() => { const fetchAllData = async () => { const [imageList, blogResponse] = await Promise.all([ listAll(imagesRef).then(res => Promise.all(res.items.map(item => getDownloadURL(item).then(url => ({ name: item.name, url })) )) ), fetch("#").then(res => res.json()) ]); setImages(imageList); const loadedBlogs:Blog[] = []; for (const key in blogResponse) { loadedBlogs.push({ id: key, title: blogResponse[key].title, desc: blogResponse[key].desc, ImageID: blogResponse[key].image, }); } setBlogs(loadedBlogs); setIsLoading(false); }; fetchAllData(); }, []); // 加载中状态展示 if (isLoading) { return <div>加载中...</div>; } return ( <div className="flexcontainer"> {/* 博客列表渲染 */} </div> );
内容的提问来源于stack exchange,提问作者Olivia Bates
相关产品推荐
相关产品推荐

