Changed data contexts to use useCallback and fixed performance issues when changing party state

This commit is contained in:
Mitchell McCaffrey
2021-01-22 14:59:05 +11:00
parent b443cdcf09
commit 3abf9c62fa
4 changed files with 341 additions and 237 deletions
+114 -75
View File
@@ -1,4 +1,10 @@
import React, { useEffect, useState, useContext } from "react";
import React, {
useEffect,
useState,
useContext,
useCallback,
useRef,
} from "react";
import * as Comlink from "comlink";
import AuthContext from "./AuthContext";
@@ -12,6 +18,8 @@ const TokenDataContext = React.createContext();
const cachedTokenMax = 100;
const worker = Comlink.wrap(new DatabaseWorker());
export function TokenDataProvider({ children }) {
const { database, databaseStatus } = useContext(DatabaseContext);
const { userId } = useContext(AuthContext);
@@ -37,7 +45,6 @@ export function TokenDataProvider({ children }) {
}
async function loadTokens() {
const worker = Comlink.wrap(new DatabaseWorker());
await worker.loadData("tokens");
const storedTokens = await worker.data;
const sortedTokens = storedTokens.sort((a, b) => b.created - a.created);
@@ -50,82 +57,28 @@ export function TokenDataProvider({ children }) {
loadTokens();
}, [userId, database, databaseStatus]);
async function addToken(token) {
await database.table("tokens").add(token);
setTokens((prevTokens) => [token, ...prevTokens]);
if (token.owner !== userId) {
await updateCache();
}
}
const tokensRef = useRef(tokens);
useEffect(() => {
tokensRef.current = tokens;
}, [tokens]);
async function removeToken(id) {
await database.table("tokens").delete(id);
setTokens((prevTokens) => {
const filtered = prevTokens.filter((token) => token.id !== id);
return filtered;
});
}
const getToken = useCallback((tokenId) => {
return tokensRef.current.find((token) => token.id === tokenId);
}, []);
async function removeTokens(ids) {
await database.table("tokens").bulkDelete(ids);
setTokens((prevTokens) => {
const filtered = prevTokens.filter((token) => !ids.includes(token.id));
return filtered;
});
}
async function updateToken(id, update) {
const change = { ...update, lastModified: Date.now() };
await database.table("tokens").update(id, change);
setTokens((prevTokens) => {
const newTokens = [...prevTokens];
const i = newTokens.findIndex((token) => token.id === id);
if (i > -1) {
newTokens[i] = { ...newTokens[i], ...change };
}
return newTokens;
});
}
async function updateTokens(ids, update) {
const change = { ...update, lastModified: Date.now() };
await Promise.all(
ids.map((id) => database.table("tokens").update(id, change))
);
setTokens((prevTokens) => {
const newTokens = [...prevTokens];
for (let id of ids) {
const i = newTokens.findIndex((token) => token.id === id);
if (i > -1) {
newTokens[i] = { ...newTokens[i], ...change };
}
}
return newTokens;
});
}
async function putToken(token) {
await database.table("tokens").put(token);
setTokens((prevTokens) => {
const newTokens = [...prevTokens];
const i = newTokens.findIndex((t) => t.id === token.id);
if (i > -1) {
newTokens[i] = { ...newTokens[i], ...token };
} else {
newTokens.unshift(token);
}
return newTokens;
});
if (token.owner !== userId) {
await updateCache();
}
}
const getTokenFromDB = useCallback(
async (tokenId) => {
let token = await database.table("tokens").get(tokenId);
return token;
},
[database]
);
/**
* Keep up to cachedTokenMax amount of tokens that you don't own
* Sorted by when they we're last used
*/
async function updateCache() {
const updateCache = useCallback(async () => {
const cachedTokens = await database
.table("tokens")
.where("owner")
@@ -141,11 +94,96 @@ export function TokenDataProvider({ children }) {
return prevTokens.filter((token) => !idsToDelete.includes(token.id));
});
}
}
}, [database, userId]);
function getToken(tokenId) {
return tokens.find((token) => token.id === tokenId);
}
const addToken = useCallback(
async (token) => {
await database.table("tokens").add(token);
setTokens((prevTokens) => [token, ...prevTokens]);
if (token.owner !== userId) {
await updateCache();
}
},
[database, updateCache, userId]
);
const removeToken = useCallback(
async (id) => {
await database.table("tokens").delete(id);
setTokens((prevTokens) => {
const filtered = prevTokens.filter((token) => token.id !== id);
return filtered;
});
},
[database]
);
const removeTokens = useCallback(
async (ids) => {
await database.table("tokens").bulkDelete(ids);
setTokens((prevTokens) => {
const filtered = prevTokens.filter((token) => !ids.includes(token.id));
return filtered;
});
},
[database]
);
const updateToken = useCallback(
async (id, update) => {
const change = { ...update, lastModified: Date.now() };
await database.table("tokens").update(id, change);
setTokens((prevTokens) => {
const newTokens = [...prevTokens];
const i = newTokens.findIndex((token) => token.id === id);
if (i > -1) {
newTokens[i] = { ...newTokens[i], ...change };
}
return newTokens;
});
},
[database]
);
const updateTokens = useCallback(
async (ids, update) => {
const change = { ...update, lastModified: Date.now() };
await Promise.all(
ids.map((id) => database.table("tokens").update(id, change))
);
setTokens((prevTokens) => {
const newTokens = [...prevTokens];
for (let id of ids) {
const i = newTokens.findIndex((token) => token.id === id);
if (i > -1) {
newTokens[i] = { ...newTokens[i], ...change };
}
}
return newTokens;
});
},
[database]
);
const putToken = useCallback(
async (token) => {
await database.table("tokens").put(token);
setTokens((prevTokens) => {
const newTokens = [...prevTokens];
const i = newTokens.findIndex((t) => t.id === token.id);
if (i > -1) {
newTokens[i] = { ...newTokens[i], ...token };
} else {
newTokens.unshift(token);
}
return newTokens;
});
if (token.owner !== userId) {
await updateCache();
}
},
[database, updateCache, userId]
);
const ownedTokens = tokens.filter((token) => token.owner === userId);
@@ -166,6 +204,7 @@ export function TokenDataProvider({ children }) {
getToken,
tokensById,
tokensLoading,
getTokenFromDB,
};
return (