Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F33305900
D6423.1768792764.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
4 KB
Referenced Files
None
Subscribers
None
D6423.1768792764.diff
View Options
diff --git a/lib/hooks/ens-cache.js b/lib/hooks/ens-cache.js
--- a/lib/hooks/ens-cache.js
+++ b/lib/hooks/ens-cache.js
@@ -1,65 +1,124 @@
// @flow
+import invariant from 'invariant';
import * as React from 'react';
import { ENSCacheContext } from '../components/ens-cache-provider.react';
import { userIdentifiedByETHAddress } from '../shared/account-utils';
import { stringForUser } from '../shared/user-utils';
-function useStringForUser(
- user: ?{ +username?: ?string, +isViewer?: ?boolean, ... },
-): ?string {
- const ethAddress = React.useMemo(() => {
- if (
- !user ||
- user.isViewer ||
- !user.username ||
- !userIdentifiedByETHAddress(user)
- ) {
- return null;
- }
- return user.username;
- }, [user]);
-
+type BaseUserInfo = { +username?: ?string, ... };
+function useENSNames<T: ?BaseUserInfo>(users: $ReadOnlyArray<T>): T[] {
const cacheContext = React.useContext(ENSCacheContext);
const { ensCache } = cacheContext;
- const cachedResult =
- ethAddress && ensCache
- ? ensCache.getCachedNameForAddress(ethAddress)
- : null;
- const [ensName, setENSName] = React.useState<?string>(null);
+ const cachedInfo = React.useMemo(
+ () =>
+ users.map(user => {
+ if (!user) {
+ return user;
+ }
+ const { username } = user;
+ const ethAddress =
+ username && userIdentifiedByETHAddress(user) ? username : null;
+ const cachedResult =
+ ethAddress && ensCache
+ ? ensCache.getCachedNameForAddress(ethAddress)
+ : null;
+ return {
+ input: user,
+ ethAddress,
+ cachedResult,
+ };
+ }),
+ [users, ensCache],
+ );
- React.useEffect(() => {
- // Whenever the ETH address changes, clear out ENS name before requery below
- setENSName(null);
- }, [ethAddress]);
+ const [fetchedAddresses, setFetchedAddresses] = React.useState<
+ $ReadOnlySet<string>,
+ >(new Set());
+ const [ensNames, setENSNames] = React.useState<$ReadOnlyMap<string, string>>(
+ new Map(),
+ );
React.useEffect(() => {
- if (cachedResult || !ethAddress || !ensCache) {
+ if (!ensCache) {
+ return;
+ }
+ const needFetch = cachedInfo
+ .map(user => {
+ if (!user) {
+ return null;
+ }
+ const { ethAddress, cachedResult } = user;
+ if (cachedResult || !ethAddress || fetchedAddresses.has(ethAddress)) {
+ return null;
+ }
+ return ethAddress;
+ })
+ .filter(Boolean);
+ if (needFetch.length === 0) {
return;
}
- let cancelled = false;
- (async () => {
- const result = await ensCache.getNameForAddress(ethAddress);
- if (result && !cancelled) {
- setENSName(result);
+ setFetchedAddresses(oldFetchedAddresses => {
+ const newFetchedAddresses = new Set(oldFetchedAddresses);
+ for (const ethAddress of needFetch) {
+ newFetchedAddresses.add(ethAddress);
}
- })();
- return () => {
- cancelled = true;
- };
- }, [cachedResult, ethAddress, ensCache]);
+ return newFetchedAddresses;
+ });
+ for (const ethAddress of needFetch) {
+ (async () => {
+ const result = await ensCache.getNameForAddress(ethAddress);
+ if (!result) {
+ return;
+ }
+ setENSNames(oldENSNames => {
+ const newENSNames = new Map(oldENSNames);
+ newENSNames.set(ethAddress, result);
+ return newENSNames;
+ });
+ })();
+ }
+ }, [cachedInfo, fetchedAddresses, ensCache]);
- if (ensName) {
- return ensName;
- } else if (cachedResult) {
- return cachedResult;
- } else if (user) {
+ return cachedInfo.map(user => {
+ if (!user) {
+ return user;
+ }
+ const { input, ethAddress, cachedResult } = user;
+ if (cachedResult) {
+ return { ...input, username: cachedResult };
+ } else if (!ethAddress) {
+ return input;
+ }
+ const ensName = ensNames.get(ethAddress);
+ if (ensName) {
+ return { ...input, username: ensName };
+ }
+ return input;
+ });
+}
+
+function useStringForUser(
+ user: ?{ +username?: ?string, +isViewer?: ?boolean, ... },
+): ?string {
+ const toFetch = user?.isViewer ? null : user;
+ // stringForUser ignores username is isViewer, so we skip the ENS fetch
+ const [result] = useENSNames([toFetch]);
+ if (user?.isViewer) {
return stringForUser(user);
+ } else if (result) {
+ return stringForUser(result);
} else {
- return null;
+ invariant(
+ !user,
+ 'the only way result can be falsey is if useENSNames is passed a ' +
+ 'falsey input, and that can only happen if useStringForUser input is ' +
+ 'falsey or isViewer is set',
+ );
+ return user;
}
}
-export { useStringForUser };
+export { useENSNames, useStringForUser };
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Jan 19, 3:19 AM (9 h, 23 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5954101
Default Alt Text
D6423.1768792764.diff (4 KB)
Attached To
Mode
D6423: [lib] Introduce useENSNames to fetch more than one ENS name at a time
Attached
Detach File
Event Timeline
Log In to Comment