Replace dexie observable with useLiveQuery
This commit is contained in:
parent
45ce2685c6
commit
3b8565ad54
@ -21,8 +21,8 @@
|
||||
"color": "^3.1.3",
|
||||
"comlink": "^4.3.0",
|
||||
"deep-diff": "^1.0.2",
|
||||
"dexie": "^3.0.3",
|
||||
"dexie-observable": "^3.0.0-beta.10",
|
||||
"dexie": "3.1.0-beta.13",
|
||||
"dexie-react-hooks": "^1.0.6",
|
||||
"err-code": "^3.0.1",
|
||||
"fake-indexeddb": "^3.1.2",
|
||||
"file-saver": "^2.0.5",
|
||||
|
@ -236,38 +236,7 @@ export function useAssetURL(assetId, type, defaultSources, unknownSource) {
|
||||
|
||||
updateAssetURL();
|
||||
|
||||
// Update the url when the asset is added to the db after the hook is used
|
||||
function handleAssetChanges(changes) {
|
||||
for (let change of changes) {
|
||||
const id = change.key;
|
||||
if (
|
||||
change.table === "assets" &&
|
||||
id === assetId &&
|
||||
(change.type === 1 || change.type === 2)
|
||||
) {
|
||||
const asset = change.obj;
|
||||
setAssetURLs((prevURLs) => {
|
||||
if (!(assetId in prevURLs)) {
|
||||
const url = URL.createObjectURL(
|
||||
new Blob([asset.file], { type: asset.mime })
|
||||
);
|
||||
return {
|
||||
...prevURLs,
|
||||
[assetId]: { url, id: assetId, references: 1 },
|
||||
};
|
||||
} else {
|
||||
return prevURLs;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
database.on("changes", handleAssetChanges);
|
||||
|
||||
return () => {
|
||||
database.on("changes").unsubscribe(handleAssetChanges);
|
||||
|
||||
// Decrease references
|
||||
setAssetURLs((prevURLs) => {
|
||||
if (assetId in prevURLs) {
|
||||
|
@ -1,9 +1,14 @@
|
||||
import React, { useEffect, useState, useContext, useCallback } from "react";
|
||||
import React, {
|
||||
useEffect,
|
||||
useState,
|
||||
useContext,
|
||||
useCallback,
|
||||
useMemo,
|
||||
} from "react";
|
||||
import { useLiveQuery } from "dexie-react-hooks";
|
||||
|
||||
import { useUserId } from "./UserIdContext";
|
||||
import { useDatabase } from "./DatabaseContext";
|
||||
|
||||
import { applyObservableChange } from "../helpers/dexie";
|
||||
import { removeGroupsItems } from "../helpers/group";
|
||||
|
||||
const MapDataContext = React.createContext();
|
||||
@ -18,33 +23,39 @@ const defaultMapState = {
|
||||
};
|
||||
|
||||
export function MapDataProvider({ children }) {
|
||||
const { database, databaseStatus } = useDatabase();
|
||||
const userId = useUserId();
|
||||
const { database } = useDatabase();
|
||||
|
||||
const mapsQuery = useLiveQuery(
|
||||
() => database?.table("maps").toArray(),
|
||||
[database]
|
||||
);
|
||||
const mapStatesQuery = useLiveQuery(
|
||||
() => database?.table("states").toArray(),
|
||||
[database]
|
||||
);
|
||||
|
||||
const maps = useMemo(() => mapsQuery || [], [mapsQuery]);
|
||||
const mapStates = useMemo(() => mapStatesQuery || [], [mapStatesQuery]);
|
||||
const mapsLoading = useMemo(
|
||||
() => !mapsQuery || !mapStatesQuery,
|
||||
[mapsQuery, mapStatesQuery]
|
||||
);
|
||||
|
||||
const mapGroupQuery = useLiveQuery(
|
||||
() => database?.table("groups").get("maps"),
|
||||
[database]
|
||||
);
|
||||
|
||||
const [maps, setMaps] = useState([]);
|
||||
const [mapStates, setMapStates] = useState([]);
|
||||
const [mapsLoading, setMapsLoading] = useState(true);
|
||||
const [mapGroups, setMapGroups] = useState([]);
|
||||
|
||||
// Load maps from the database and ensure state is properly setup
|
||||
useEffect(() => {
|
||||
if (!userId || !database || databaseStatus === "loading") {
|
||||
return;
|
||||
}
|
||||
|
||||
async function loadMaps() {
|
||||
const storedMaps = await database.table("maps").toArray();
|
||||
setMaps(storedMaps);
|
||||
const storedStates = await database.table("states").toArray();
|
||||
setMapStates(storedStates);
|
||||
async function updateMapGroups() {
|
||||
const group = await database.table("groups").get("maps");
|
||||
const storedGroups = group.items;
|
||||
setMapGroups(storedGroups);
|
||||
setMapsLoading(false);
|
||||
setMapGroups(group.items);
|
||||
}
|
||||
|
||||
loadMaps();
|
||||
}, [userId, database, databaseStatus]);
|
||||
if (database && mapGroupQuery) {
|
||||
updateMapGroups();
|
||||
}
|
||||
}, [mapGroupQuery, database]);
|
||||
|
||||
const getMap = useCallback(
|
||||
async (mapId) => {
|
||||
@ -138,77 +149,6 @@ export function MapDataProvider({ children }) {
|
||||
[database]
|
||||
);
|
||||
|
||||
// Create DB observable to sync creating and deleting
|
||||
useEffect(() => {
|
||||
if (!database || databaseStatus === "loading") {
|
||||
return;
|
||||
}
|
||||
|
||||
function handleMapChanges(changes) {
|
||||
for (let change of changes) {
|
||||
if (change.table === "maps") {
|
||||
if (change.type === 1) {
|
||||
// Created
|
||||
const map = change.obj;
|
||||
const state = { ...defaultMapState, mapId: map.id };
|
||||
setMaps((prevMaps) => [map, ...prevMaps]);
|
||||
setMapStates((prevStates) => [state, ...prevStates]);
|
||||
} else if (change.type === 2) {
|
||||
const map = change.obj;
|
||||
setMaps((prevMaps) => {
|
||||
const newMaps = [...prevMaps];
|
||||
const i = newMaps.findIndex((m) => m.id === map.id);
|
||||
if (i > -1) {
|
||||
newMaps[i] = map;
|
||||
}
|
||||
return newMaps;
|
||||
});
|
||||
} else if (change.type === 3) {
|
||||
// Deleted
|
||||
const id = change.key;
|
||||
setMaps((prevMaps) => {
|
||||
const filtered = prevMaps.filter((map) => map.id !== id);
|
||||
return filtered;
|
||||
});
|
||||
setMapStates((prevMapsStates) => {
|
||||
const filtered = prevMapsStates.filter(
|
||||
(state) => state.mapId !== id
|
||||
);
|
||||
return filtered;
|
||||
});
|
||||
}
|
||||
}
|
||||
if (change.table === "states") {
|
||||
if (change.type === 2) {
|
||||
// Update map state
|
||||
const state = change.obj;
|
||||
setMapStates((prevMapStates) => {
|
||||
const newStates = [...prevMapStates];
|
||||
const i = newStates.findIndex((s) => s.mapId === state.mapId);
|
||||
if (i > -1) {
|
||||
newStates[i] = state;
|
||||
}
|
||||
return newStates;
|
||||
});
|
||||
}
|
||||
}
|
||||
if (change.table === "groups") {
|
||||
if (change.type === 2 && change.key === "maps") {
|
||||
const group = applyObservableChange(change);
|
||||
const groups = group.items.filter((item) => item !== null);
|
||||
setMapGroups(groups);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
database.on("changes", handleMapChanges);
|
||||
|
||||
return () => {
|
||||
database.on("changes").unsubscribe(handleMapChanges);
|
||||
};
|
||||
}, [database, databaseStatus]);
|
||||
|
||||
const [mapsById, setMapsById] = useState({});
|
||||
useEffect(() => {
|
||||
setMapsById(
|
||||
|
@ -1,37 +1,44 @@
|
||||
import React, { useEffect, useState, useContext, useCallback } from "react";
|
||||
import React, {
|
||||
useEffect,
|
||||
useState,
|
||||
useContext,
|
||||
useCallback,
|
||||
useMemo,
|
||||
} from "react";
|
||||
import { useLiveQuery } from "dexie-react-hooks";
|
||||
|
||||
import { useUserId } from "./UserIdContext";
|
||||
import { useDatabase } from "./DatabaseContext";
|
||||
|
||||
import { applyObservableChange } from "../helpers/dexie";
|
||||
import { removeGroupsItems } from "../helpers/group";
|
||||
|
||||
const TokenDataContext = React.createContext();
|
||||
|
||||
export function TokenDataProvider({ children }) {
|
||||
const { database, databaseStatus } = useDatabase();
|
||||
const userId = useUserId();
|
||||
const { database } = useDatabase();
|
||||
|
||||
const tokensQuery = useLiveQuery(
|
||||
() => database?.table("tokens").toArray(),
|
||||
[database]
|
||||
);
|
||||
|
||||
const tokens = useMemo(() => tokensQuery || [], [tokensQuery]);
|
||||
const tokensLoading = useMemo(() => !tokensQuery, [tokensQuery]);
|
||||
|
||||
const tokenGroupQuery = useLiveQuery(
|
||||
() => database?.table("groups").get("tokens"),
|
||||
[database]
|
||||
);
|
||||
|
||||
const [tokens, setTokens] = useState([]);
|
||||
const [tokensLoading, setTokensLoading] = useState(true);
|
||||
const [tokenGroups, setTokenGroups] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!userId || !database || databaseStatus === "loading") {
|
||||
return;
|
||||
}
|
||||
|
||||
async function loadTokens() {
|
||||
const storedTokens = await database.table("tokens").toArray();
|
||||
setTokens(storedTokens);
|
||||
async function updateTokenGroups() {
|
||||
const group = await database.table("groups").get("tokens");
|
||||
const storedGroups = group.items;
|
||||
setTokenGroups(storedGroups);
|
||||
setTokensLoading(false);
|
||||
setTokenGroups(group.items);
|
||||
}
|
||||
|
||||
loadTokens();
|
||||
}, [userId, database, databaseStatus]);
|
||||
if (database && tokenGroupQuery) {
|
||||
updateTokenGroups();
|
||||
}
|
||||
}, [tokenGroupQuery, database]);
|
||||
|
||||
const getToken = useCallback(
|
||||
async (tokenId) => {
|
||||
@ -83,15 +90,15 @@ export function TokenDataProvider({ children }) {
|
||||
|
||||
const updateTokensHidden = useCallback(
|
||||
async (ids, hideInSidebar) => {
|
||||
// Update immediately to avoid UI delay
|
||||
setTokens((prevTokens) => {
|
||||
let newTokens = [...prevTokens];
|
||||
for (let id of ids) {
|
||||
const tokenIndex = newTokens.findIndex((token) => token.id === id);
|
||||
newTokens[tokenIndex].hideInSidebar = hideInSidebar;
|
||||
}
|
||||
return newTokens;
|
||||
});
|
||||
// // Update immediately to avoid UI delay
|
||||
// setTokens((prevTokens) => {
|
||||
// let newTokens = [...prevTokens];
|
||||
// for (let id of ids) {
|
||||
// const tokenIndex = newTokens.findIndex((token) => token.id === id);
|
||||
// newTokens[tokenIndex].hideInSidebar = hideInSidebar;
|
||||
// }
|
||||
// return newTokens;
|
||||
// });
|
||||
await Promise.all(
|
||||
ids.map((id) => database.table("tokens").update(id, { hideInSidebar }))
|
||||
);
|
||||
@ -108,67 +115,6 @@ export function TokenDataProvider({ children }) {
|
||||
[database]
|
||||
);
|
||||
|
||||
// Create DB observable to sync creating and deleting
|
||||
useEffect(() => {
|
||||
if (!database || databaseStatus === "loading") {
|
||||
return;
|
||||
}
|
||||
|
||||
function handleTokenChanges(changes) {
|
||||
// Pool token changes together to call a single state update at the end
|
||||
let tokensCreated = [];
|
||||
let tokensUpdated = {};
|
||||
let tokensDeleted = [];
|
||||
for (let change of changes) {
|
||||
if (change.table === "tokens") {
|
||||
if (change.type === 1) {
|
||||
// Created
|
||||
const token = change.obj;
|
||||
tokensCreated.push(token);
|
||||
} else if (change.type === 2) {
|
||||
// Updated
|
||||
const token = change.obj;
|
||||
tokensUpdated[token.id] = token;
|
||||
} else if (change.type === 3) {
|
||||
// Deleted
|
||||
const id = change.key;
|
||||
tokensDeleted.push(id);
|
||||
}
|
||||
}
|
||||
if (change.table === "groups") {
|
||||
if (change.type === 2 && change.key === "tokens") {
|
||||
const group = applyObservableChange(change);
|
||||
const groups = group.items.filter((item) => item !== null);
|
||||
setTokenGroups(groups);
|
||||
}
|
||||
}
|
||||
}
|
||||
const tokensUpdatedArray = Object.values(tokensUpdated);
|
||||
if (
|
||||
tokensCreated.length > 0 ||
|
||||
tokensUpdatedArray.length > 0 ||
|
||||
tokensDeleted.length > 0
|
||||
) {
|
||||
setTokens((prevTokens) => {
|
||||
let newTokens = [...tokensCreated, ...prevTokens];
|
||||
for (let token of tokensUpdatedArray) {
|
||||
const tokenIndex = newTokens.findIndex((t) => t.id === token.id);
|
||||
if (tokenIndex > -1) {
|
||||
newTokens[tokenIndex] = token;
|
||||
}
|
||||
}
|
||||
return newTokens.filter((token) => !tokensDeleted.includes(token.id));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
database.on("changes", handleTokenChanges);
|
||||
|
||||
return () => {
|
||||
database.on("changes").unsubscribe(handleTokenChanges);
|
||||
};
|
||||
}, [database, databaseStatus]);
|
||||
|
||||
const [tokensById, setTokensById] = useState({});
|
||||
useEffect(() => {
|
||||
setTokensById(
|
||||
|
@ -1,7 +1,6 @@
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
import Dexie, { DexieOptions } from "dexie";
|
||||
import { v4 as uuid } from "uuid";
|
||||
import "dexie-observable";
|
||||
|
||||
import { loadVersions } from "./upgrade";
|
||||
import { getDefaultMaps } from "./maps";
|
||||
|
15
yarn.lock
15
yarn.lock
@ -5369,12 +5369,17 @@ detect-port-alt@1.1.6:
|
||||
address "^1.0.1"
|
||||
debug "^2.6.0"
|
||||
|
||||
dexie-observable@^3.0.0-beta.10:
|
||||
version "3.0.0-beta.10"
|
||||
resolved "https://registry.yarnpkg.com/dexie-observable/-/dexie-observable-3.0.0-beta.10.tgz#ad7a7e136defbb62f9eab9198a5cb9e10bce1c87"
|
||||
integrity sha512-GMPwQMLh1nYqM1MYsOZudsIwSMqDMrAOBxNuw+Y2ijsrQTBPi3nRF2CinY02IdlmffkaU7DsDfnlgdaMEaiHTQ==
|
||||
dexie-react-hooks@^1.0.6:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/dexie-react-hooks/-/dexie-react-hooks-1.0.6.tgz#a21d116addb2bb785507bf924cc6e963d858d5d5"
|
||||
integrity sha512-OFoOBC4BQzkVGicuWl/cIMtlPp0wTAnUXwUJzq+l/zp0XVGmwEWkemRFq7JbudJLT0DINFVVzgVhGV7KOUK7uA==
|
||||
|
||||
"dexie@^3.0.0-alpha.5 || ^2.0.4", dexie@^3.0.3:
|
||||
dexie@3.1.0-beta.13:
|
||||
version "3.1.0-beta.13"
|
||||
resolved "https://registry.yarnpkg.com/dexie/-/dexie-3.1.0-beta.13.tgz#54b3438e2aca3b60f87a823a535ce1b4313056ec"
|
||||
integrity sha512-pUcX9YyX1VDjF1oMqiOys6N2zoXIA/CeTghB3P4Ee77U8n9q0qa2pmNYoHyyYPKLU58+gzsMJuOc6HLPJDQrQQ==
|
||||
|
||||
"dexie@^3.0.0-alpha.5 || ^2.0.4":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/dexie/-/dexie-3.0.3.tgz#ede63849dfe5f07e13e99bb72a040e8ac1d29dab"
|
||||
integrity sha512-BSFhGpngnCl1DOr+8YNwBDobRMH0ziJs2vts69VilwetHYOtEDcLqo7d/XiIphM0tJZ2rPPyAGd31lgH2Ln3nw==
|
||||
|
Loading…
Reference in New Issue
Block a user