无法对未安装的组件 useEffect 错误执行 React 状态更新
Can't perform a React state update on an unmounted component useEffect error
我有这段代码,我在其中获取数据并将其传递给组件。然后这个子组件呈现我制作的数据,这样当用户从顶部下拉时,组件将刷新但是每当我刷新 first time only
时,我都会收到错误
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
代码如下:
function FolloweringScreens({
data,
screen,
username,
navigation,
noMoreData,
setLoadingMore,
lastVisible,
setNoMoreData,
setLastVisible,
setfollowingData,
loadingMore,
setLoading,
currentuser,
}) {
const [stateData, setStateData] = useState();
const [refresh, setRefresh] = useState(false);
useEffect(() => {
const setState = () => setStateData(data);
return setState();
}, [data, refresh]);
// Refresh
const handleFetch = () => {
setRefresh(true);
const cleanup = fetchData(
username,
setfollowingData,
setLoading,
setLastVisible,
setNoMoreData,
setRefresh,
screen,
currentuser,
);
return cleanup;
};
return (
<>
<FlatList
refreshing={refresh}
onRefresh={handleFetch}
data={stateData}
keyExtractor={(i, index) => index.toString()}
renderItem={({item, index}) => {
return (
<>
{ Using my data here }
</>
);
}}
/>
</>
);
}
export default FolloweringScreens;
这里是 fetchData 函数:
export const fetchData = (
username,
setfollowingData,
setLoading,
setLastVisible,
setNoMoreData,
setRefresh,
screen,
currentuser,
) => {
const dataaRef = firestore().collection('usernames');
setNoMoreData && setNoMoreData(false);
// If in
dataaRef // Go to whichever users clicked on data
.doc(username.toLowerCase())
.collection(screen) // Go to followers/following
.orderBy('followedAt')
.limit(6)
.get()
.then((snapshot) => {
setLoading(true);
snapshot.empty
? null
: setLastVisible(
snapshot.docs[snapshot.docs.length - 1].data().followedAt,
);
let promises = [];
// 1b. For each document, return that document data
snapshot.forEach((doc) => {
const data = doc.data();
promises.push(
data.path.get().then((res) => {
const userData = res.data();
// Go to logged in users directory to see
// if they are following these users in this
// users following/followers page so we can
// differentiate whether to display follow/unfollow button
return dataaRef
.doc(
currentuser === undefined
? username.toLowerCase()
: currentuser.toLowerCase(),
)
.collection('Following')
.doc(doc.id)
.get()
.then((searchedDocs) => {
return {
profileName: doc.id ? doc.id : null,
displayName: userData.displayName
? userData.displayName
: null,
followerCount:
userData.followers !== undefined ? userData.followers : 0,
followingCount:
userData.following !== undefined ? userData.following : 0,
imageUrl: userData.imageUrl ? userData.imageUrl : null,
isFollowed: searchedDocs.exists ? true : false,
};
});
}),
);
});
// 1c. set All document data to followingData
Promise.all(promises).then((res) => {
setfollowingData(res);
// console.log('res', res);
});
setLoading(false);
setRefresh && setRefresh(false);
});
};
实际上你不能那样做。由于 useEffect 中的 returns 函数充当清理函数。你通常会清理你的背部,比如在处理组件时删除事件监听器和类似的东西。
useEffect(() => {
document.addEventListenter('click', () => {});
function cleanup() {
document.removeEventListener('click', () => {});
};
return cleanup;
})
这就是 useEffect 的工作原理。因此,在您的情况下,当组件被卸载时,它会抱怨状态更新,这在 React 世界中是非法的。
如果你想调用它就调用它。
useEffect(() => {
const setState = () => setStateData(data);
setState();
}, [data, refresh]);
或者更好的方法是在 useEffect 之外定义您的函数,然后在其中调用它。
const setState = () => setStateData(data);
useEffect(() => {
if (!data) return;
setState();
}, [data, refresh]);
我有这段代码,我在其中获取数据并将其传递给组件。然后这个子组件呈现我制作的数据,这样当用户从顶部下拉时,组件将刷新但是每当我刷新 first time only
时,我都会收到错误
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
代码如下:
function FolloweringScreens({
data,
screen,
username,
navigation,
noMoreData,
setLoadingMore,
lastVisible,
setNoMoreData,
setLastVisible,
setfollowingData,
loadingMore,
setLoading,
currentuser,
}) {
const [stateData, setStateData] = useState();
const [refresh, setRefresh] = useState(false);
useEffect(() => {
const setState = () => setStateData(data);
return setState();
}, [data, refresh]);
// Refresh
const handleFetch = () => {
setRefresh(true);
const cleanup = fetchData(
username,
setfollowingData,
setLoading,
setLastVisible,
setNoMoreData,
setRefresh,
screen,
currentuser,
);
return cleanup;
};
return (
<>
<FlatList
refreshing={refresh}
onRefresh={handleFetch}
data={stateData}
keyExtractor={(i, index) => index.toString()}
renderItem={({item, index}) => {
return (
<>
{ Using my data here }
</>
);
}}
/>
</>
);
}
export default FolloweringScreens;
这里是 fetchData 函数:
export const fetchData = (
username,
setfollowingData,
setLoading,
setLastVisible,
setNoMoreData,
setRefresh,
screen,
currentuser,
) => {
const dataaRef = firestore().collection('usernames');
setNoMoreData && setNoMoreData(false);
// If in
dataaRef // Go to whichever users clicked on data
.doc(username.toLowerCase())
.collection(screen) // Go to followers/following
.orderBy('followedAt')
.limit(6)
.get()
.then((snapshot) => {
setLoading(true);
snapshot.empty
? null
: setLastVisible(
snapshot.docs[snapshot.docs.length - 1].data().followedAt,
);
let promises = [];
// 1b. For each document, return that document data
snapshot.forEach((doc) => {
const data = doc.data();
promises.push(
data.path.get().then((res) => {
const userData = res.data();
// Go to logged in users directory to see
// if they are following these users in this
// users following/followers page so we can
// differentiate whether to display follow/unfollow button
return dataaRef
.doc(
currentuser === undefined
? username.toLowerCase()
: currentuser.toLowerCase(),
)
.collection('Following')
.doc(doc.id)
.get()
.then((searchedDocs) => {
return {
profileName: doc.id ? doc.id : null,
displayName: userData.displayName
? userData.displayName
: null,
followerCount:
userData.followers !== undefined ? userData.followers : 0,
followingCount:
userData.following !== undefined ? userData.following : 0,
imageUrl: userData.imageUrl ? userData.imageUrl : null,
isFollowed: searchedDocs.exists ? true : false,
};
});
}),
);
});
// 1c. set All document data to followingData
Promise.all(promises).then((res) => {
setfollowingData(res);
// console.log('res', res);
});
setLoading(false);
setRefresh && setRefresh(false);
});
};
实际上你不能那样做。由于 useEffect 中的 returns 函数充当清理函数。你通常会清理你的背部,比如在处理组件时删除事件监听器和类似的东西。
useEffect(() => {
document.addEventListenter('click', () => {});
function cleanup() {
document.removeEventListener('click', () => {});
};
return cleanup;
})
这就是 useEffect 的工作原理。因此,在您的情况下,当组件被卸载时,它会抱怨状态更新,这在 React 世界中是非法的。
如果你想调用它就调用它。
useEffect(() => {
const setState = () => setStateData(data);
setState();
}, [data, refresh]);
或者更好的方法是在 useEffect 之外定义您的函数,然后在其中调用它。
const setState = () => setStateData(data);
useEffect(() => {
if (!data) return;
setState();
}, [data, refresh]);