Replace dexie observable with useLiveQuery
This commit is contained in:
parent
45ce2685c6
commit
3b8565ad54
@ -21,8 +21,8 @@
|
|||||||
"color": "^3.1.3",
|
"color": "^3.1.3",
|
||||||
"comlink": "^4.3.0",
|
"comlink": "^4.3.0",
|
||||||
"deep-diff": "^1.0.2",
|
"deep-diff": "^1.0.2",
|
||||||
"dexie": "^3.0.3",
|
"dexie": "3.1.0-beta.13",
|
||||||
"dexie-observable": "^3.0.0-beta.10",
|
"dexie-react-hooks": "^1.0.6",
|
||||||
"err-code": "^3.0.1",
|
"err-code": "^3.0.1",
|
||||||
"fake-indexeddb": "^3.1.2",
|
"fake-indexeddb": "^3.1.2",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
|
@ -236,38 +236,7 @@ export function useAssetURL(assetId, type, defaultSources, unknownSource) {
|
|||||||
|
|
||||||
updateAssetURL();
|
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 () => {
|
return () => {
|
||||||
database.on("changes").unsubscribe(handleAssetChanges);
|
|
||||||
|
|
||||||
// Decrease references
|
// Decrease references
|
||||||
setAssetURLs((prevURLs) => {
|
setAssetURLs((prevURLs) => {
|
||||||
if (assetId in 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 { useDatabase } from "./DatabaseContext";
|
||||||
|
|
||||||
import { applyObservableChange } from "../helpers/dexie";
|
|
||||||
import { removeGroupsItems } from "../helpers/group";
|
import { removeGroupsItems } from "../helpers/group";
|
||||||
|
|
||||||
const MapDataContext = React.createContext();
|
const MapDataContext = React.createContext();
|
||||||
@ -18,33 +23,39 @@ const defaultMapState = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function MapDataProvider({ children }) {
|
export function MapDataProvider({ children }) {
|
||||||
const { database, databaseStatus } = useDatabase();
|
const { database } = useDatabase();
|
||||||
const userId = useUserId();
|
|
||||||
|
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([]);
|
const [mapGroups, setMapGroups] = useState([]);
|
||||||
|
|
||||||
// Load maps from the database and ensure state is properly setup
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!userId || !database || databaseStatus === "loading") {
|
async function updateMapGroups() {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadMaps() {
|
|
||||||
const storedMaps = await database.table("maps").toArray();
|
|
||||||
setMaps(storedMaps);
|
|
||||||
const storedStates = await database.table("states").toArray();
|
|
||||||
setMapStates(storedStates);
|
|
||||||
const group = await database.table("groups").get("maps");
|
const group = await database.table("groups").get("maps");
|
||||||
const storedGroups = group.items;
|
setMapGroups(group.items);
|
||||||
setMapGroups(storedGroups);
|
|
||||||
setMapsLoading(false);
|
|
||||||
}
|
}
|
||||||
|
if (database && mapGroupQuery) {
|
||||||
loadMaps();
|
updateMapGroups();
|
||||||
}, [userId, database, databaseStatus]);
|
}
|
||||||
|
}, [mapGroupQuery, database]);
|
||||||
|
|
||||||
const getMap = useCallback(
|
const getMap = useCallback(
|
||||||
async (mapId) => {
|
async (mapId) => {
|
||||||
@ -138,77 +149,6 @@ export function MapDataProvider({ children }) {
|
|||||||
[database]
|
[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({});
|
const [mapsById, setMapsById] = useState({});
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setMapsById(
|
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 { useDatabase } from "./DatabaseContext";
|
||||||
|
|
||||||
import { applyObservableChange } from "../helpers/dexie";
|
|
||||||
import { removeGroupsItems } from "../helpers/group";
|
import { removeGroupsItems } from "../helpers/group";
|
||||||
|
|
||||||
const TokenDataContext = React.createContext();
|
const TokenDataContext = React.createContext();
|
||||||
|
|
||||||
export function TokenDataProvider({ children }) {
|
export function TokenDataProvider({ children }) {
|
||||||
const { database, databaseStatus } = useDatabase();
|
const { database } = useDatabase();
|
||||||
const userId = useUserId();
|
|
||||||
|
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([]);
|
const [tokenGroups, setTokenGroups] = useState([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!userId || !database || databaseStatus === "loading") {
|
async function updateTokenGroups() {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadTokens() {
|
|
||||||
const storedTokens = await database.table("tokens").toArray();
|
|
||||||
setTokens(storedTokens);
|
|
||||||
const group = await database.table("groups").get("tokens");
|
const group = await database.table("groups").get("tokens");
|
||||||
const storedGroups = group.items;
|
setTokenGroups(group.items);
|
||||||
setTokenGroups(storedGroups);
|
|
||||||
setTokensLoading(false);
|
|
||||||
}
|
}
|
||||||
|
if (database && tokenGroupQuery) {
|
||||||
loadTokens();
|
updateTokenGroups();
|
||||||
}, [userId, database, databaseStatus]);
|
}
|
||||||
|
}, [tokenGroupQuery, database]);
|
||||||
|
|
||||||
const getToken = useCallback(
|
const getToken = useCallback(
|
||||||
async (tokenId) => {
|
async (tokenId) => {
|
||||||
@ -83,15 +90,15 @@ export function TokenDataProvider({ children }) {
|
|||||||
|
|
||||||
const updateTokensHidden = useCallback(
|
const updateTokensHidden = useCallback(
|
||||||
async (ids, hideInSidebar) => {
|
async (ids, hideInSidebar) => {
|
||||||
// Update immediately to avoid UI delay
|
// // Update immediately to avoid UI delay
|
||||||
setTokens((prevTokens) => {
|
// setTokens((prevTokens) => {
|
||||||
let newTokens = [...prevTokens];
|
// let newTokens = [...prevTokens];
|
||||||
for (let id of ids) {
|
// for (let id of ids) {
|
||||||
const tokenIndex = newTokens.findIndex((token) => token.id === id);
|
// const tokenIndex = newTokens.findIndex((token) => token.id === id);
|
||||||
newTokens[tokenIndex].hideInSidebar = hideInSidebar;
|
// newTokens[tokenIndex].hideInSidebar = hideInSidebar;
|
||||||
}
|
// }
|
||||||
return newTokens;
|
// return newTokens;
|
||||||
});
|
// });
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
ids.map((id) => database.table("tokens").update(id, { hideInSidebar }))
|
ids.map((id) => database.table("tokens").update(id, { hideInSidebar }))
|
||||||
);
|
);
|
||||||
@ -108,67 +115,6 @@ export function TokenDataProvider({ children }) {
|
|||||||
[database]
|
[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({});
|
const [tokensById, setTokensById] = useState({});
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTokensById(
|
setTokensById(
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
import Dexie, { DexieOptions } from "dexie";
|
import Dexie, { DexieOptions } from "dexie";
|
||||||
import { v4 as uuid } from "uuid";
|
import { v4 as uuid } from "uuid";
|
||||||
import "dexie-observable";
|
|
||||||
|
|
||||||
import { loadVersions } from "./upgrade";
|
import { loadVersions } from "./upgrade";
|
||||||
import { getDefaultMaps } from "./maps";
|
import { getDefaultMaps } from "./maps";
|
||||||
|
17
yarn.lock
17
yarn.lock
@ -5369,12 +5369,17 @@ detect-port-alt@1.1.6:
|
|||||||
address "^1.0.1"
|
address "^1.0.1"
|
||||||
debug "^2.6.0"
|
debug "^2.6.0"
|
||||||
|
|
||||||
dexie-observable@^3.0.0-beta.10:
|
dexie-react-hooks@^1.0.6:
|
||||||
version "3.0.0-beta.10"
|
version "1.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/dexie-observable/-/dexie-observable-3.0.0-beta.10.tgz#ad7a7e136defbb62f9eab9198a5cb9e10bce1c87"
|
resolved "https://registry.yarnpkg.com/dexie-react-hooks/-/dexie-react-hooks-1.0.6.tgz#a21d116addb2bb785507bf924cc6e963d858d5d5"
|
||||||
integrity sha512-GMPwQMLh1nYqM1MYsOZudsIwSMqDMrAOBxNuw+Y2ijsrQTBPi3nRF2CinY02IdlmffkaU7DsDfnlgdaMEaiHTQ==
|
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"
|
version "3.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/dexie/-/dexie-3.0.3.tgz#ede63849dfe5f07e13e99bb72a040e8ac1d29dab"
|
resolved "https://registry.yarnpkg.com/dexie/-/dexie-3.0.3.tgz#ede63849dfe5f07e13e99bb72a040e8ac1d29dab"
|
||||||
integrity sha512-BSFhGpngnCl1DOr+8YNwBDobRMH0ziJs2vts69VilwetHYOtEDcLqo7d/XiIphM0tJZ2rPPyAGd31lgH2Ln3nw==
|
integrity sha512-BSFhGpngnCl1DOr+8YNwBDobRMH0ziJs2vts69VilwetHYOtEDcLqo7d/XiIphM0tJZ2rPPyAGd31lgH2Ln3nw==
|
||||||
@ -7202,7 +7207,7 @@ image-outline@^0.1.0:
|
|||||||
marching-squares "^0.2.0"
|
marching-squares "^0.2.0"
|
||||||
minimist "^1.2.0"
|
minimist "^1.2.0"
|
||||||
ndarray "^1.0.18"
|
ndarray "^1.0.18"
|
||||||
|
|
||||||
immediate@~3.0.5:
|
immediate@~3.0.5:
|
||||||
version "3.0.6"
|
version "3.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
|
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
|
||||||
|
Loading…
Reference in New Issue
Block a user