我正在使用钩子将React组件从类组件转换为功能组件。
我想从数据库中获取组成员的列表。我将数组保持在组件状态。
const [members, setMembers] = useState([]);
成员下载后,我想异步获取每个成员的个人资料图片。
1)组件已安装,并调用以下useEffect()
。请注意对getMembers
的依赖性。
useEffect(() => {
getMembers();
}, [getMembers]);
2)useEffect
回调调用函数getMembers()
。请注意对getMembersProfilePictures
的依赖性。
const getMembers = useCallback(() => {
fetchMembersFromDatabase()
.then((data) => {
setMembers(data);
getMembersProfilePictures();
})
}, [getMembersProfilePictures]);
3)一旦从数据库中检索到成员,members
状态就会更新并调用getMembersProfilePictures()
。请注意对members
的依赖性。
const getMembersProfilePictures = useCallback(() => {
for (let i = 0; i < members.length; i++) {
const member = { ...members[i] };
if (member.has_picture) {
firebase
.storage()
.ref()
.child("<childUrl>")
.getDownloadURL()
.then((url) => {
member.picture_url = url;
const membersCopy = [...members];
membersCopy[i] = member;
setMembers(membersCopy);
});
}
}
}, [members]);
由于useEffect()
依赖于getMembers()
,getMembers()
依赖于getMembersProfilePictures()
,而getMembersProfilePictures()
依赖于members
,因此{ {1}}状态被更新,members
的链被重新创建,并且useCallback()
被调用。这成为数据获取的无限循环。
我目前的想法是将从useEffect()
检索到的数据作为参数直接传递给fetchMembersFromDatabase()
。这从getMembersProfilePictures()
中删除了members
的依存关系,因此删除了无限循环。
忽略侦听数据库中成员列表中的更改,并忽略成员及其各自的个人资料图片的缓存,看来此解决方案没有缺点。我想知道其他人对此解决方案有何想法。谢谢!
答案 0 :(得分:2)
fetchMembersFromDatabase()
中呼叫useCallback
,但
不将其用作依赖项。members
内设置getMembersProfilePictures()
,其中
使用成员作为依赖项。这导致我的无限循环
意见。useEffect
没有任何依赖关系useEffect
用于会员和致电
获取成员图像功能。为成员维护另一个对象
缩略图。答案 1 :(得分:1)
编辑:很明显,您试图在一个组件中做太多事情。
您真正想做的是
Member
组件,然后Member
组件下载自己的图片。下面是半伪代码,将async / await内容加一点盐,然后按照适合您的方式来做:
const MemberList = ({maybeWithAProp}) => {
const [members,setMembers] = useState([]);
useEffect(async () => {
setMembers((await someCallToGetMembers(maybeWithAProp));
},[maybeWithAProp]);
return members.map(m => <Member {...m}/>
}
const Member = ({memberId}) => {
const [pic,setPic] = useState();
useEffect(async () => {
setPic(null); // you're about to download a new one, probably get rid of the old one first
setPic((await fetchPicForMember(memberId));
},[memberId]);
return (...)
}
原始答案:
是否考虑过分开您的州?
const [members, setMembers] = useState([]);
const [membersPics,setMembersPics] = useState([]);
// run on mount only
useEffect(async () => {
const data = await fetchMembersFromDatabase();
setMembers(data);
,[]);
useEffect(async () => {
const pics = await Promise.all(members.map(m => fetchProfilePic(m)));
setMembersPics(pics);
},[members]);
return <SomeComponent members={useMemo(members.map((m,i) => ({...m,url:membersPics[i]})),[members,memberPics])}/>
原始代码的主要问题是您两次调用setMembers
,这很重要地表明您认为是一种状态,最好将其视为两种状态。