React使用Firebase查询数据更新state后组件未重新渲染问题
问题根源
你代码的核心问题是forEach不支持等待异步回调执行完成:
- 你在
forEach的回调里用了async/await调用getDownloadURL,但Array.prototype.forEach不会等待这些异步操作执行完毕,就会直接执行后续的setWho(filteredArray)代码 - 调用
setWho的时间点,所有图片下载地址的请求还没有返回,filteredArray此时还是空数组,所以你实际上第一次更新给state的是空数组 - 后续异步请求完成往
filteredArray里push元素属于直接修改已有数组的引用,React的state浅比较检测不到这种突变,所以不会触发重渲染 - 你在控制台看到
who有值是因为控制台打印的是数组的引用,当你展开控制台打印内容的时候,异步操作已经完成,数组已经被后续push操作修改,才会显示有3个元素,不代表setState的时候数组就有值。
修复方案
把forEach遍历换成map返回Promise数组,再用Promise.all等待所有异步操作执行完成后再更新state:
const storage = getStorage(firebaseApp); const db = getFirestore(); function Aside() { const [who, setWho] = useState([]) const whoToFollow = async () => { const usersRef = collection(db, "users"); const q = query(usersRef, limit(3)); const querySnapshot = await getDocs(q); const results = querySnapshot.docs.map(doc => doc.data()); // 用Promise.all等待所有异步请求完成 const filteredArray = await Promise.all( results.map(async (user) => { const imgPath = await getDownloadURL(ref(storage, user.profilePicture)); return { uid: user.UID, displayName: user.displayName, userName: user.userName, profilePicture: imgPath }; }) ); console.log('Users recieved and updating who state') setWho(filteredArray) } useEffect(() => { console.log('component did mount, calling "WhoToFollow()" function') whoToFollow() }, []); useEffect(() => { console.log('who state has been updated but nothing is being rendered?') console.log(who) }, [who]); return ( <aside> <div className='aside-head'>Search</div> <div className='aside-cont'> <div className='who-to-follow'> <div className='wtf-head'> New users to follow </div> <div className='wtf-list'> {who.length} </div> </div> </div> </aside> ); } export default Aside;
修复后filteredArray是所有异步操作完成后生成的全新数组,state更新会触发组件正常重渲染,页面上就会显示正确的数组长度3。
内容的提问来源于stack exchange,提问作者Jacob Riches
相关产品推荐
相关产品推荐

