-
Notifications
You must be signed in to change notification settings - Fork 368
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
🔬 Make useRawLogs more efficient and responsive (#1151)
* Make useRawLogs more efficient and responsive - Makes use of isStatic query param - Makes use of refresh query param and global config - Clears logs when there's a change in the filter to minimize the amount of time invalid old logs are returned - Prevents some race conditions - It no longer fetches logs with every re-render - Filter can no longer be a promise - reduces unnecessary complexity * Improve useRawLogs - Switch back to allowing filter promises - Switch back to useEffect to update the logs - Shallow copy filter data before the async getLogs to prevent data mismatch making logs stale - Prevent changing state after component unmount - Use useRef to track loading status * Fix and simplify nullish checking in deepEqual * Remove comment in deepEqual * Cleanup useResolvedFilter * Move isPrimitive and deepEqual to common helper * Fix bug in deepEqual * Add comment to deepEqual * Make slight deepEqual performance improvement * Add tests for deepEqual and isPrimitive * Export common in helpers * Extract useResolvedFilter to useResolvedPromise * Add tests for useResolvedPromise * Remove unused import * Fix code smell * Disable unused var linting * Improve performance of useResolvedPromise * Fix staleness issue * Fix bugs in useResolvedPromise * Disable buggy optimization * Create hot-pots-tap.md --------- Co-authored-by: Justyna Broniszewska <[email protected]> Co-authored-by: Łukasz Stankiewicz <[email protected]>
- Loading branch information
1 parent
5a626b8
commit fb44f98
Showing
8 changed files
with
489 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@usedapp/core": patch | ||
--- | ||
|
||
🔬 Make useRawLogs more efficient and responsive |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,269 @@ | ||
import { expect } from 'chai' | ||
import { deepEqual, isPrimitive } from './common' | ||
import { Filter } from '@ethersproject/abstract-provider' | ||
|
||
describe('common', function () { | ||
describe('isPrimitive', function () { | ||
it('Returns true for 0', function () { | ||
expect(isPrimitive(0)).to.equal(true) | ||
}) | ||
|
||
it('Returns true for 1', function () { | ||
expect(isPrimitive(1)).to.equal(true) | ||
}) | ||
|
||
it("Returns true for 'a'", function () { | ||
expect(isPrimitive('a')).to.equal(true) | ||
}) | ||
|
||
it("Returns true for ''", function () { | ||
expect(isPrimitive('')).to.equal(true) | ||
}) | ||
|
||
it('Returns true for undefined', function () { | ||
expect(isPrimitive(undefined)).to.equal(true) | ||
}) | ||
|
||
it('Returns true for null', function () { | ||
expect(isPrimitive(null)).to.equal(true) | ||
}) | ||
|
||
it('Returns true for true', function () { | ||
expect(isPrimitive(true)).to.equal(true) | ||
}) | ||
|
||
it('Returns true for false', function () { | ||
expect(isPrimitive(false)).to.equal(true) | ||
}) | ||
|
||
it('Returns false for []', function () { | ||
expect(isPrimitive([])).to.equal(false) | ||
}) | ||
|
||
it('Returns false for {}', function () { | ||
expect(isPrimitive({})).to.equal(false) | ||
}) | ||
}) | ||
|
||
describe('deepEqual', function () { | ||
it('Returns true for 0 and 0', function () { | ||
expect(deepEqual(0, 0)).to.equal(true) | ||
}) | ||
|
||
it('Returns true for 1 and 1', function () { | ||
expect(deepEqual(1, 1)).to.equal(true) | ||
}) | ||
|
||
it("Returns true for 'a' and 'a'", function () { | ||
expect(deepEqual('a', 'a')).to.equal(true) | ||
}) | ||
|
||
it("Returns true for '' and ''", function () { | ||
expect(deepEqual('', '')).to.equal(true) | ||
}) | ||
|
||
it('Returns true for undefined and undefined', function () { | ||
expect(deepEqual(undefined, undefined)).to.equal(true) | ||
}) | ||
|
||
it('Returns true for null and null', function () { | ||
expect(deepEqual(null, null)).to.equal(true) | ||
}) | ||
|
||
it('Returns true for true and true', function () { | ||
expect(deepEqual(true, true)).to.equal(true) | ||
}) | ||
|
||
it('Returns true for false and false', function () { | ||
expect(deepEqual(false, false)).to.equal(true) | ||
}) | ||
|
||
it('Returns true for [] and []', function () { | ||
expect(deepEqual([], [])).to.equal(true) | ||
}) | ||
|
||
it('Returns true for undefined and null', function () { | ||
expect(deepEqual(undefined, null)).to.equal(true) | ||
}) | ||
|
||
it('Returns true for null and undefined', function () { | ||
expect(deepEqual(null, undefined)).to.equal(true) | ||
}) | ||
|
||
it('Returns true for two block filters with different property orderings', function () { | ||
const filter1: Filter = { | ||
fromBlock: 1, | ||
toBlock: 2, | ||
} | ||
|
||
const filter2: Filter = { | ||
toBlock: 2, | ||
fromBlock: 1, | ||
} | ||
|
||
expect(deepEqual(filter1, filter2)).to.equal(true) | ||
}) | ||
|
||
it('Returns false for two block filters with different property counts (one has less than two)', function () { | ||
const filter1: Filter = { | ||
fromBlock: 1, | ||
} | ||
|
||
const filter2: Filter = { | ||
fromBlock: 1, | ||
toBlock: 2, | ||
} | ||
|
||
expect(deepEqual(filter1, filter2)).to.equal(false) | ||
}) | ||
|
||
it('Returns false for two block filters with different property counts (one has more than two)', function () { | ||
const filter1: Filter = { | ||
fromBlock: 1, | ||
toBlock: 2, | ||
} | ||
|
||
const filter2: Filter = { | ||
fromBlock: 1, | ||
} | ||
|
||
expect(deepEqual(filter1, filter2)).to.equal(false) | ||
}) | ||
|
||
it('Returns false for two block filters with different addresses', function () { | ||
const filter1: Filter = { | ||
address: '0x0000000000000000000000000000000000000000', | ||
} | ||
|
||
const filter2: Filter = { | ||
address: '0x0000000000000000000000000000000000000001', | ||
} | ||
|
||
expect(deepEqual(filter1, filter2)).to.equal(false) | ||
}) | ||
|
||
it("Returns false for 0 and '0'", function () { | ||
expect(deepEqual(0, '0')).to.equal(false) | ||
}) | ||
|
||
it("Returns false for '0' and 0", function () { | ||
expect(deepEqual('0', 0)).to.equal(false) | ||
}) | ||
|
||
it('Returns false for false and 0', function () { | ||
expect(deepEqual(false, 0)).to.equal(false) | ||
}) | ||
|
||
it('Returns false for 0 and false', function () { | ||
expect(deepEqual(0, false)).to.equal(false) | ||
}) | ||
|
||
it('Returns false for 0 and null', function () { | ||
expect(deepEqual(0, null)).to.equal(false) | ||
}) | ||
|
||
it('Returns false for null and 0', function () { | ||
expect(deepEqual(null, 0)).to.equal(false) | ||
}) | ||
|
||
it('Returns false for 0 and undefined', function () { | ||
expect(deepEqual(0, undefined)).to.equal(false) | ||
}) | ||
|
||
it('Returns false for undefined and 0', function () { | ||
expect(deepEqual(undefined, 0)).to.equal(false) | ||
}) | ||
|
||
it("Returns false for '' and null", function () { | ||
expect(deepEqual('', null)).to.equal(false) | ||
}) | ||
|
||
it("Returns false for null and ''", function () { | ||
expect(deepEqual(null, '')).to.equal(false) | ||
}) | ||
|
||
it("Returns false for '' and undefined", function () { | ||
expect(deepEqual('', undefined)).to.equal(false) | ||
}) | ||
|
||
it("Returns false for undefined and ''", function () { | ||
expect(deepEqual(undefined, '')).to.equal(false) | ||
}) | ||
|
||
it('Returns false for {} and {}', function () { | ||
expect(deepEqual({}, {})).to.equal(true) | ||
}) | ||
|
||
it('Returns false for 0 and 1', function () { | ||
expect(deepEqual(0, 1)).to.equal(false) | ||
}) | ||
|
||
it('Returns false for 1 and 0', function () { | ||
expect(deepEqual(1, 0)).to.equal(false) | ||
}) | ||
|
||
it("Returns false for 'a' and 'b'", function () { | ||
expect(deepEqual('a', 'b')).to.equal(false) | ||
}) | ||
|
||
it("Returns false for 'b' and 'a'", function () { | ||
expect(deepEqual('b', 'a')).to.equal(false) | ||
}) | ||
|
||
it("Returns false for '' and 'a'", function () { | ||
expect(deepEqual('', 'a')).to.equal(false) | ||
}) | ||
|
||
it("Returns false for 'a' and ''", function () { | ||
expect(deepEqual('a', '')).to.equal(false) | ||
}) | ||
|
||
it('Retuens false for [0] and [0, 0]', function () { | ||
expect(deepEqual([0], [0, 0])).to.equal(false) | ||
}) | ||
|
||
it('Returns false for [0, 0] and [0]', function () { | ||
expect(deepEqual([0, 0], [0])).to.equal(false) | ||
}) | ||
|
||
it('Returns false for [0] and [1]', function () { | ||
expect(deepEqual([0], [1])).to.equal(false) | ||
}) | ||
|
||
it('Returns false for [1] and [0]', function () { | ||
expect(deepEqual([1], [0])).to.equal(false) | ||
}) | ||
|
||
it('Returns false for [0] and [null]', function () { | ||
expect(deepEqual([0], [null])).to.equal(false) | ||
}) | ||
|
||
it('Returns false for [null] and [0]', function () { | ||
expect(deepEqual([null], [0])).to.equal(false) | ||
}) | ||
|
||
it('Returns false for [0] and [undefined]', function () { | ||
expect(deepEqual([0], [undefined])).to.equal(false) | ||
}) | ||
|
||
it('Returns false for [undefined] and [0]', function () { | ||
expect(deepEqual([undefined], [0])).to.equal(false) | ||
}) | ||
|
||
it('Returns false for [0] and [{}]', function () { | ||
expect(deepEqual([0], [{}])).to.equal(false) | ||
}) | ||
|
||
it('Returns false for [{}] and [0]', function () { | ||
expect(deepEqual([{}], [0])).to.equal(false) | ||
}) | ||
|
||
it('Returns false for [0, 1] and [1, 0]', function () { | ||
expect(deepEqual([0, 1], [1, 0])).to.equal(false) | ||
}) | ||
|
||
it('Returns false for [1, 0] and [0, 1]', function () { | ||
expect(deepEqual([1, 0], [0, 1])).to.equal(false) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,47 @@ | ||
export function shortenString(str: string) { | ||
return str.substring(0, 6) + '...' + str.substring(str.length - 4) | ||
} | ||
|
||
/** | ||
* Determines whether two objects are equal using a deep comparison. Null and undefined are considered equal. Arrays | ||
* with the same elements are not considered equal if they are in different orders. Objects with the same properties | ||
* can have different property orderings and still be considered equal. | ||
* @param obj1 The first object to compare. | ||
* @param obj2 The second object to compare. | ||
* @returns True if the objects are deep equal, false otherwise. | ||
*/ | ||
export function deepEqual(obj1: any, obj2: any) { | ||
if (obj1 === obj2) return true | ||
|
||
if (obj1 == null || obj2 == null) return obj1 == obj2 | ||
|
||
const obj1Primitive = isPrimitive(obj1) | ||
const obj2Primitive = isPrimitive(obj2) | ||
if (obj1Primitive || obj2Primitive) | ||
// compare primitives | ||
return obj1Primitive === obj2Primitive && obj1 === obj2 | ||
|
||
let obj1KeyCount = 0 | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
for (const _ in obj1) obj1KeyCount++ | ||
|
||
let obj2KeyCount = 0 | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
for (const _ in obj2) { | ||
if (++obj2KeyCount > obj1KeyCount) return false | ||
} | ||
|
||
if (obj1KeyCount !== obj2KeyCount) return false | ||
|
||
// compare objects with same number of keys | ||
for (const key in obj1) { | ||
if (!(key in obj2)) return false //other object doesn't have this prop | ||
if (!deepEqual(obj1[key], obj2[key])) return false | ||
} | ||
|
||
return true | ||
} | ||
|
||
export function isPrimitive(obj: any) { | ||
return obj !== Object(obj) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
fb44f98
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉 Published on https://usedapp-docs.netlify.app as production
🚀 Deployed on https://6654513d7d713966e349f8b8--usedapp-docs.netlify.app
fb44f98
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉 Published on https://example.usedapp.io as production
🚀 Deployed on https://665451439bc177af4e8876bd--usedapp-example.netlify.app
fb44f98
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉 Published on https://usedapp.io as production
🚀 Deployed on https://6654514930bad95db3e61a88--usedapp-website.netlify.app