Fix blank page on loading ERC tokens; use indexedDb instead of localStorage to store tokens list (#100)

pull/101/head
Artem 3 years ago committed by GitHub
parent e20bda1478
commit 5606805a8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 22
      src/components/ERC1155_Pool.tsx
  2. 20
      src/components/ERC20_Pool.tsx
  3. 20
      src/components/ERC721_Pool.tsx
  4. 25
      src/hooks/ERC1155_Pool.ts
  5. 25
      src/hooks/ERC20_Pool.ts
  6. 25
      src/hooks/ERC721_Pool.ts
  7. 6
      src/pages/AddressPage/TokenInfo.tsx
  8. 2
      src/pages/ERC20List/ERC20Table.tsx
  9. 84
      src/utils/indexedDB.ts

@ -1,6 +1,7 @@
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { getAllERC1155 } from "src/api/client"; import { getAllERC1155 } from "src/api/client";
import { setERC1155Pool, ERC1155 } from "src/hooks/ERC1155_Pool"; import { setERC1155Pool, ERC1155 } from "src/hooks/ERC1155_Pool";
import { IndexedDbKeyPath, IndexedDbStore, saveToIndexedDB } from "../utils/indexedDB";
export function ERC1155_Pool() { export function ERC1155_Pool() {
useEffect(() => { useEffect(() => {
@ -8,14 +9,21 @@ export function ERC1155_Pool() {
const getRates = async () => { const getRates = async () => {
try { try {
const erc1155: ERC1155[] = await getAllERC1155();
const erc1155Map = {} as Record<string, ERC1155>; const erc1155Map = {} as Record<string, ERC1155>;
erc1155.forEach((i: any) => { let erc1155: ERC1155[] = await getAllERC1155();
erc1155Map[i.address] = i; erc1155 = erc1155.map(item => {
}); erc1155Map[item.address] = item;
return {
window.localStorage.setItem("ERC1155_Pool", JSON.stringify(erc1155Map)); [IndexedDbKeyPath]: item.address,
...item
}
})
setERC1155Pool(erc1155Map); setERC1155Pool(erc1155Map);
await saveToIndexedDB(IndexedDbStore.ERC1155Pool, erc1155)
localStorage.setItem(IndexedDbStore.ERC1155Pool, '1')
console.log(`ERC1155 tokens is updated, count: ${erc1155.length}`)
} catch (e) {
console.error('Cannot update ERC1155 tokens', (e as Error).message)
} finally { } finally {
clearTimeout(tId); clearTimeout(tId);
tId = window.setTimeout(getRates, 10 * 60 * 1e3); tId = window.setTimeout(getRates, 10 * 60 * 1e3);
@ -26,7 +34,7 @@ export function ERC1155_Pool() {
() => { () => {
getRates(); getRates();
}, },
window.localStorage.getItem("ERC1155_Pool") ? 2200 : 0 window.localStorage.getItem(IndexedDbStore.ERC1155Pool) ? 2200 : 0
); );
return () => { return () => {

@ -1,6 +1,7 @@
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { getAllERC20 } from "src/api/client"; import { getAllERC20 } from "src/api/client";
import { setERC20Pool, Erc20 } from "src/hooks/ERC20_Pool"; import { setERC20Pool, Erc20 } from "src/hooks/ERC20_Pool";
import { IndexedDbKeyPath, IndexedDbStore, saveToIndexedDB } from "../utils/indexedDB";
export function ERC20_Pool() { export function ERC20_Pool() {
useEffect(() => { useEffect(() => {
@ -8,14 +9,21 @@ export function ERC20_Pool() {
const getRates = async () => { const getRates = async () => {
try { try {
const erc20: Erc20[] = await getAllERC20(); let erc20: Erc20[] = await getAllERC20();
const erc20Map = {} as Record<string, Erc20>; const erc20Map = {} as Record<string, Erc20>;
erc20.forEach((i: any) => { erc20 = erc20.map((item) => {
erc20Map[i.address] = i; erc20Map[item.address] = item;
return {
[IndexedDbKeyPath]: item.address,
...item
}
}); });
window.localStorage.setItem("ERC20_Pool", JSON.stringify(erc20Map));
setERC20Pool(erc20Map); setERC20Pool(erc20Map);
await saveToIndexedDB(IndexedDbStore.ERC20Pool, erc20)
localStorage.setItem(IndexedDbStore.ERC20Pool, '1')
console.log(`ERC20 tokens updated, count: ${erc20.length}`)
} catch (e) {
console.error('Cannot update ERC20 tokens', (e as Error).message)
} finally { } finally {
window.clearTimeout(tId); window.clearTimeout(tId);
tId = window.setTimeout(getRates, 10 * 60 * 1e3); tId = window.setTimeout(getRates, 10 * 60 * 1e3);
@ -26,7 +34,7 @@ export function ERC20_Pool() {
() => { () => {
getRates(); getRates();
}, },
window.localStorage.getItem("ERC20_Pool") ? 2000 : 0 window.localStorage.getItem(IndexedDbStore.ERC20Pool) ? 2000 : 0
); );
return () => { return () => {

@ -1,6 +1,7 @@
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { getAllERC721 } from "src/api/client"; import { getAllERC721 } from "src/api/client";
import { setERC721Pool, ERC721 } from "src/hooks/ERC721_Pool"; import { setERC721Pool, ERC721 } from "src/hooks/ERC721_Pool";
import { IndexedDbKeyPath, IndexedDbStore, saveToIndexedDB } from "../utils/indexedDB";
export function ERC721_Pool() { export function ERC721_Pool() {
useEffect(() => { useEffect(() => {
@ -8,14 +9,21 @@ export function ERC721_Pool() {
const getRates = async () => { const getRates = async () => {
try { try {
const erc721: ERC721[] = await getAllERC721(); let erc721: ERC721[] = await getAllERC721();
const erc721Map = {} as Record<string, ERC721>; const erc721Map = {} as Record<string, ERC721>;
erc721.forEach((i: any) => { erc721 = erc721.map((item) => {
erc721Map[i.address] = i; erc721Map[item.address] = item;
return {
[IndexedDbKeyPath]: item.address,
...item
}
}); });
window.localStorage.setItem("ERC721_Pool", JSON.stringify(erc721Map));
setERC721Pool(erc721Map); setERC721Pool(erc721Map);
await saveToIndexedDB(IndexedDbStore.ERC721Pool, erc721)
localStorage.setItem(IndexedDbStore.ERC721Pool, '1')
console.log(`ERC721 tokens is updated, count: ${erc721.length}`)
} catch (e) {
console.error('Cannot update ERC721 tokens', (e as Error).message)
} finally { } finally {
clearTimeout(tId); clearTimeout(tId);
tId = window.setTimeout(getRates, 10 * 60 * 1e3); tId = window.setTimeout(getRates, 10 * 60 * 1e3);
@ -26,7 +34,7 @@ export function ERC721_Pool() {
() => { () => {
getRates(); getRates();
}, },
window.localStorage.getItem("ERC721_Pool") ? 2100 : 0 window.localStorage.getItem(IndexedDbStore.ERC721Pool) ? 2100 : 0
); );
return () => { return () => {

@ -1,5 +1,6 @@
import { useState } from "react"; import { useEffect, useState } from "react";
import { singletonHook } from "react-singleton-hook"; import { singletonHook } from "react-singleton-hook";
import { IndexedDbStore, loadFromIndexedDB } from "../utils/indexedDB";
const initValue: ERC1155_Pool = {}; const initValue: ERC1155_Pool = {};
@ -8,12 +9,24 @@ let globalSetMode = () => {
}; };
export const useERC1155Pool = singletonHook(initValue, () => { export const useERC1155Pool = singletonHook(initValue, () => {
const pool = const getPool = async () => {
(JSON.parse( try {
window.localStorage.getItem("ERC1155_Pool") || "{}" const erc1155 = await loadFromIndexedDB(IndexedDbStore.ERC1155Pool)
) as ERC1155_Pool) || initValue; const erc1155Map = {} as Record<string, ERC1155>;
erc1155.forEach(item => {
erc1155Map[item.address] = item;
})
setMode(erc1155Map)
} catch (e) {
console.error('Cannot get ERC1155 records: ', (e as Error).message)
}
}
const [mode, setMode] = useState<ERC1155_Pool>(pool); useEffect(() => {
getPool()
}, [])
const [mode, setMode] = useState<ERC1155_Pool>(initValue);
//@ts-ignore //@ts-ignore
globalSetMode = setMode; globalSetMode = setMode;
return mode; return mode;

@ -1,5 +1,6 @@
import { useState } from "react"; import { useEffect, useState } from "react";
import { singletonHook } from "react-singleton-hook"; import { singletonHook } from "react-singleton-hook";
import { IndexedDbStore, loadFromIndexedDB } from "../utils/indexedDB";
const initValue: ERC20_Pool = {}; const initValue: ERC20_Pool = {};
@ -8,12 +9,24 @@ let globalSetMode = () => {
}; };
export const useERC20Pool = singletonHook(initValue, () => { export const useERC20Pool = singletonHook(initValue, () => {
const pool = const getPool = async () => {
(JSON.parse( try {
window.localStorage.getItem("ERC20_Pool") || "{}" const erc20 = await loadFromIndexedDB(IndexedDbStore.ERC20Pool)
) as ERC20_Pool) || initValue; const erc20Map = {} as Record<string, Erc20>;
erc20.forEach(item => {
erc20Map[item.address] = item;
})
setMode(erc20Map)
} catch (e) {
console.error('Cannot get ERC20 records: ', (e as Error).message)
}
}
const [mode, setMode] = useState<ERC20_Pool>(pool); useEffect(() => {
getPool()
}, [])
const [mode, setMode] = useState<ERC20_Pool>(initValue);
//@ts-ignore //@ts-ignore
globalSetMode = setMode; globalSetMode = setMode;
return mode; return mode;

@ -1,5 +1,6 @@
import { useState } from "react"; import { useEffect, useState } from "react";
import { singletonHook } from "react-singleton-hook"; import { singletonHook } from "react-singleton-hook";
import { IndexedDbStore, loadFromIndexedDB } from "../utils/indexedDB";
const initValue: ERC721_Pool = {}; const initValue: ERC721_Pool = {};
@ -8,12 +9,24 @@ let globalSetMode = () => {
}; };
export const useERC721Pool = singletonHook(initValue, () => { export const useERC721Pool = singletonHook(initValue, () => {
const pool = const getPool = async () => {
(JSON.parse( try {
window.localStorage.getItem("ERC721_Pool") || "{}" const erc721 = await loadFromIndexedDB(IndexedDbStore.ERC721Pool)
) as ERC721_Pool) || initValue; const erc721Map = {} as Record<string, ERC721>;
erc721.forEach(item => {
erc721Map[item.address] = item;
})
setMode(erc721Map)
} catch (e) {
console.error('Cannot get ERC721 records: ', (e as Error).message)
}
}
const [mode, setMode] = useState<ERC721_Pool>(pool); useEffect(() => {
getPool()
}, [])
const [mode, setMode] = useState<ERC721_Pool>(initValue);
//@ts-ignore //@ts-ignore
globalSetMode = setMode; globalSetMode = setMode;
return mode; return mode;

@ -45,7 +45,7 @@ export function TokensInfo(props: { value: Token[] }) {
const erc20Tokens = value const erc20Tokens = value
.filter((i) => filterWithBalance(i.balance)) .filter((i) => filterWithBalance(i.balance))
.filter((i) => i.isERC20) .filter((i) => i.isERC20 && erc20Map[i.tokenAddress])
.map((item) => ({ .map((item) => ({
...item, ...item,
symbol: erc20Map[item.tokenAddress].symbol, symbol: erc20Map[item.tokenAddress].symbol,
@ -55,7 +55,7 @@ export function TokensInfo(props: { value: Token[] }) {
const erc721Tokens = value const erc721Tokens = value
.filter((i) => filterWithBalance(i.balance)) .filter((i) => filterWithBalance(i.balance))
.filter((i) => i.isERC721) .filter((i) => i.isERC721 && erc721Map[i.tokenAddress])
.map((item) => ({ .map((item) => ({
...item, ...item,
symbol: erc721Map[item.tokenAddress].symbol, symbol: erc721Map[item.tokenAddress].symbol,
@ -64,7 +64,7 @@ export function TokensInfo(props: { value: Token[] }) {
const erc1155Tokens = value const erc1155Tokens = value
.filter((i) => filterWithBalance(i.balance)) .filter((i) => filterWithBalance(i.balance))
.filter((i) => i.isERC1155) .filter((i) => i.isERC1155 && erc1155Map[i.tokenAddress])
.map((item) => ({ .map((item) => ({
...item, ...item,
symbol: erc1155Map[item.tokenAddress].symbol, symbol: erc1155Map[item.tokenAddress].symbol,

@ -152,7 +152,7 @@ function getColumns(props: any) {
render: (data: Erc20) => <Address address={data.address} displayHash />, render: (data: Erc20) => <Address address={data.address} displayHash />,
}, },
{ {
property: "totalSupply", property: "circulatingSupply",
size: "small", size: "small",
resizeable: false, resizeable: false,
header: ( header: (

@ -0,0 +1,84 @@
export enum IndexedDbStore {
ERC1155Pool = 'ERC1155_Pool',
ERC20Pool = 'ERC20_Pool',
ERC721Pool = 'ERC721_Pool',
}
export const IndexedDbKeyPath = '_id'
const DbVersion = 1
export const saveToIndexedDB = (storeName: IndexedDbStore, objects: any[]) => {
return new Promise(
function(resolve, reject) {
const dbRequest = indexedDB.open(storeName, DbVersion);
dbRequest.onerror = function() {
reject(Error('IndexedDB error'));
};
dbRequest.onupgradeneeded = function(event) {
// @ts-ignore
const db = event.target.result;
db.createObjectStore(storeName, { keyPath: IndexedDbKeyPath });
};
dbRequest.onsuccess = function() {
let db = dbRequest.result;
db.onversionchange = function() {
db.close();
console.log('Database is outdated, please reload the page');
};
const transaction = db.transaction([storeName], 'readwrite');
const objectStore = transaction.objectStore(storeName);
objects.forEach((item, i, arr) => {
const objectRequest = objectStore.put(item);
if (i === arr.length - 1) {
objectRequest.onsuccess = function() {
resolve('Data saved');
};
}
})
};
dbRequest.onblocked = function() {
reject(Error(`IndexedDB ${storeName} is blocked`));
};
}
);
}
export const loadFromIndexedDB = (storeName: IndexedDbStore): Promise<any[]> => {
return new Promise(
function(resolve, reject) {
const dbRequest = indexedDB.open(storeName, DbVersion);
dbRequest.onerror = function() {
reject(Error('IndexedDB error'));
};
dbRequest.onupgradeneeded = function(event) {
// @ts-ignore
event.target.transaction.abort();
reject(Error('Not found'));
};
dbRequest.onsuccess = function(event) {
// @ts-ignore
const database = event.target.result;
const transaction = database.transaction([storeName]);
const objectStore = transaction.objectStore(storeName);
const objectRequest = objectStore.getAll();
objectRequest.onerror = function(e: Error) {
reject(Error(`Indexed db error: ${e.message}`));
};
objectRequest.onsuccess = function(event: any) {
if (objectRequest.result) resolve(objectRequest.result);
else reject(Error('Objects is not found'));
};
};
}
);
}
Loading…
Cancel
Save