我正在 React Native 中创建一个依赖于实时更新的应用程序。当一个用户在他们的会话中更新数据时,另一个用户需要立即看到该更新而无需刷新他们的应用程序。我正在使用 RTK 查询来管理我的商店,但如果我在查询中使用 onSnapShot,则无法弄清楚如何关闭内存泄漏。我需要考虑另一个 Redux 解决方案吗?
我试过通过 props 传递数据来管理数据,但是当使用复杂的组件时,管理变得有点复杂。
我从组件中的以下内容开始,但想将其移动到 api:
export const teamPlayersApi = createApi({
reducerPath: "teamPlayers",
baseQuery: fakeBaseQuery(),
tagTypes: ["TeamPlayer"],
endpoints: (builder) => ({
fetchTeamPlayersByMatchId: builder.query({
async queryFn(matchId) {
let players = [];
return new Promise((resolve, reject) => {
const playersRef = query(
collection(db, "teamPlayers"),
where("playerMatchId", "==", matchId)
);
//real time update
onSnapshot(playersRef, (snapshot) => {
players = snapshot.docs.map((doc) => ({
id: doc.id,
player: doc.data()
}));
resolve({ data: players });
});
});
}
})
})
})
这有两个不同的部分:
queryFn
使用 onValue
获取初始数据。这是您的查询进入 loading
状态并在某个时刻以第一个值结束的点。onCacheEntryAdded
生命周期函数调用 onSnapshot
,更新值并保持订阅。这是在您的组件使用缓存条目时生成订阅并使用新值更新您的数据的点。export const teamPlayersApi = createApi({
reducerPath: "teamPlayers",
baseQuery: fakeBaseQuery(),
tagTypes: ["TeamPlayer"],
endpoints: (builder) => ({
fetchTeamPlayersByMatchId: builder.query({
async queryFn(matchId) {
let players = [];
return {
data: await new Promise((resolve, reject) => {
const playersRef = query(
collection(db, "teamPlayers"),
where("playerMatchId", "==", matchId)
);
// probably more logic here to get your final shape
onValue(
playersRef,
(snapshot) => resolve(snapshot.toJSON()),
reject
);
}),
};
},
async onCacheEntryAdded(
matchId,
{ updateCachedData, cacheDataLoaded, cacheEntryRemoved }
) {
let unsubscribe = () => {};
try {
await cacheDataLoaded;
const playersRef = query(
collection(db, "teamPlayers"),
where("playerMatchId", "==", matchId)
);
unsubscribe = onSnapshot(playersRef, (snapshot) => {
players = snapshot.docs.map((doc) => ({
id: doc.id,
player: doc.data(),
}));
updateCachedData((draft) => {
// or whatever you want to do
draft.push(players);
});
});
} catch {}
await cacheEntryRemoved;
unsubscribe();
},
}),
}),
});
嗨 @phry 下面是我正在使用的代码,它正确调试显示草稿正在更新,但我如何“听”那些变化?实施如下:
const {
data: fetchPlayersData,
error: fetchPlayersError,
isFetching: isFetchingPlayers
} = useFetchTeamPlayersStreambyMatchIdQuery(matchId);
useEffect(() => {
console.log("players changed");
}, [fetchPlayersData]);
fetchTeamPlayersStreambyMatchId: builder.query({
async queryFn(matchId) {
try {
const teamPlayersRef = collection(db, "teamPlayers");
const tpq = query(
teamPlayersRef,
where("playerMatchId", "==", matchId)
);
const querySnap = await getDocs(tpq);
let players = [];
querySnap.forEach((doc) => {
return players.push({
id: doc.id,
player: doc.data()
});
});
return { data: players };
} catch (error) {
console.error(error.message);
return { error: error.message };
}
},
async onCacheEntryAdded(
matchId,
{ updateCachedData, cacheDataLoaded, cacheEntryRemoved }
) {
let unsubscribe = () => {};
try {
await cacheDataLoaded;
const playersRef = query(
collection(db, "teamPlayers"),
where("playerMatchId", "==", matchId)
);
unsubscribe = onSnapshot(playersRef, (snapshot) => {
players = snapshot.docs.map((doc) => ({
id: doc.id,
player: doc.data()
}));
updateCachedData((draft) => {
draft = [];
draft.push(players);
});
});
} catch {}
await cacheEntryRemoved;
unsubscribe();
}
})