From 32f955693fcc01285cf073288af83e1bd0374da3 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 9 Mar 2022 15:08:04 -0800 Subject: [PATCH] fix: restructure web3 to memoize (#3472) --- src/lib/components/Web3Provider.tsx | 40 ------------------ src/lib/components/Widget.tsx | 2 +- src/lib/hooks/useActiveWeb3React.ts | 19 --------- src/lib/hooks/useActiveWeb3React.tsx | 63 ++++++++++++++++++++++++++++ src/lib/state/web3.ts | 11 ----- 5 files changed, 64 insertions(+), 71 deletions(-) delete mode 100644 src/lib/components/Web3Provider.tsx delete mode 100644 src/lib/hooks/useActiveWeb3React.ts create mode 100644 src/lib/hooks/useActiveWeb3React.tsx delete mode 100644 src/lib/state/web3.ts diff --git a/src/lib/components/Web3Provider.tsx b/src/lib/components/Web3Provider.tsx deleted file mode 100644 index ad4365779a..0000000000 --- a/src/lib/components/Web3Provider.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { initializeConnector } from '@web3-react/core' -import { EIP1193 } from '@web3-react/eip1193' -import { Actions, Connector, Provider as Eip1193Provider } from '@web3-react/types' -import { Url } from '@web3-react/url' -import { SetStateAction } from 'jotai' -import { RESET, useUpdateAtom } from 'jotai/utils' -import { injectedAtom, urlAtom, Web3ReactState } from 'lib/state/web3' -import { ReactNode, useEffect } from 'react' - -interface Web3ProviderProps { - jsonRpcEndpoint?: string - provider?: Eip1193Provider - children: ReactNode -} - -function useConnector( - Connector: T, - initializer: I | undefined, - setContext: (update: typeof RESET | SetStateAction) => void -) { - return useEffect(() => { - if (initializer) { - const state = initializeConnector((actions) => new Connector(actions, initializer)) - state[0].activate() - setContext(state) - } else { - setContext(RESET) - } - }, [Connector, initializer, setContext]) -} - -export default function Web3Provider({ jsonRpcEndpoint, provider, children }: Web3ProviderProps) { - const setUrl = useUpdateAtom(urlAtom) - useConnector(Url, jsonRpcEndpoint, setUrl) - - const setInjected = useUpdateAtom(injectedAtom) - useConnector(EIP1193, provider, setInjected) - - return <>{children} -} diff --git a/src/lib/components/Widget.tsx b/src/lib/components/Widget.tsx index cacd20de8f..2106843647 100644 --- a/src/lib/components/Widget.tsx +++ b/src/lib/components/Widget.tsx @@ -3,6 +3,7 @@ import { Provider as Eip1193Provider } from '@web3-react/types' import { DEFAULT_LOCALE, SupportedLocale } from 'constants/locales' import { Provider as AtomProvider } from 'jotai' import { TransactionsUpdater } from 'lib/hooks/transactions' +import { Web3Provider } from 'lib/hooks/useActiveWeb3React' import { BlockUpdater } from 'lib/hooks/useBlockNumber' import useEip1193Provider from 'lib/hooks/useEip1193Provider' import { UNMOUNTING } from 'lib/hooks/useUnmount' @@ -15,7 +16,6 @@ import { Provider as ReduxProvider } from 'react-redux' import { Modal, Provider as DialogProvider } from './Dialog' import ErrorBoundary, { ErrorHandler } from './Error/ErrorBoundary' import WidgetPropValidator from './Error/WidgetsPropsValidator' -import Web3Provider from './Web3Provider' const WidgetWrapper = styled.div<{ width?: number | string }>` -moz-osx-font-smoothing: grayscale; diff --git a/src/lib/hooks/useActiveWeb3React.ts b/src/lib/hooks/useActiveWeb3React.ts deleted file mode 100644 index 212693b649..0000000000 --- a/src/lib/hooks/useActiveWeb3React.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Web3ReactHooks } from '@web3-react/core' -import { useAtomValue } from 'jotai/utils' -import { injectedAtom, urlAtom, Web3ReactState } from 'lib/state/web3' - -export function useActiveWeb3ReactState(): Web3ReactState { - const injected = useAtomValue(injectedAtom) - const url = useAtomValue(urlAtom) - return injected[1].useIsActive() ? injected : url -} - -export function useActiveWeb3ReactHooks(): Web3ReactHooks { - const [, hooks] = useActiveWeb3ReactState() - return hooks -} - -export default function useActiveWeb3React() { - const { useProvider, useWeb3React } = useActiveWeb3ReactHooks() - return useWeb3React(useProvider()) -} diff --git a/src/lib/hooks/useActiveWeb3React.tsx b/src/lib/hooks/useActiveWeb3React.tsx new file mode 100644 index 0000000000..3b2ad3d449 --- /dev/null +++ b/src/lib/hooks/useActiveWeb3React.tsx @@ -0,0 +1,63 @@ +import { getPriorityConnector, initializeConnector, Web3ReactHooks } from '@web3-react/core' +import { EIP1193 } from '@web3-react/eip1193' +import { EMPTY } from '@web3-react/empty' +import { Actions, Connector, Provider as Eip1193Provider } from '@web3-react/types' +import { Url } from '@web3-react/url' +import { useAtom, WritableAtom } from 'jotai' +import { useAtomValue } from 'jotai/utils' +import { atomWithDefault, RESET, useUpdateAtom } from 'jotai/utils' +import { PropsWithChildren, useEffect } from 'react' + +const [connector, hooks] = initializeConnector(() => EMPTY) +const EMPTY_CONNECTOR: [Connector, Web3ReactHooks] = [connector, hooks] +const urlConnectorAtom = atomWithDefault<[Connector, Web3ReactHooks]>(() => EMPTY_CONNECTOR) +const injectedConnectorAtom = atomWithDefault<[Connector, Web3ReactHooks]>(() => EMPTY_CONNECTOR) +const web3Atom = atomWithDefault>(() => ({ + connector: EMPTY_CONNECTOR[0], + library: undefined, + chainId: undefined, + account: undefined, + active: false, + error: undefined, +})) + +export default function useActiveWeb3React() { + return useAtomValue(web3Atom) +} + +function useConnector( + connectorAtom: WritableAtom<[Connector, Web3ReactHooks], typeof RESET | [Connector, Web3ReactHooks]>, + Connector: T, + initializer: I | undefined +) { + const [connector, setConnector] = useAtom(connectorAtom) + useEffect(() => { + if (initializer) { + const [connector, hooks] = initializeConnector((actions) => new Connector(actions, initializer)) + connector.activate() + setConnector([connector, hooks]) + } else { + setConnector(RESET) + } + }, [Connector, initializer, setConnector]) + return connector +} + +interface Web3ProviderProps { + provider?: Eip1193Provider + jsonRpcEndpoint?: string +} + +export function Web3Provider({ provider, jsonRpcEndpoint, children }: PropsWithChildren) { + const injectedConnector = useConnector(injectedConnectorAtom, EIP1193, provider) + const urlConnector = useConnector(urlConnectorAtom, Url, jsonRpcEndpoint) + const priorityConnector = getPriorityConnector(injectedConnector, urlConnector) + const priorityProvider = priorityConnector.usePriorityProvider() + const priorityWeb3React = priorityConnector.usePriorityWeb3React(priorityProvider) + const setWeb3 = useUpdateAtom(web3Atom) + useEffect(() => { + setWeb3(priorityWeb3React) + }, [priorityWeb3React, setWeb3]) + + return <>{children} +} diff --git a/src/lib/state/web3.ts b/src/lib/state/web3.ts deleted file mode 100644 index aa8f88ae46..0000000000 --- a/src/lib/state/web3.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { initializeConnector, Web3ReactHooks } from '@web3-react/core' -import { EMPTY } from '@web3-react/empty' -import { Connector, Web3ReactStore } from '@web3-react/types' -import { atomWithDefault } from 'jotai/utils' - -export type Web3ReactState = [Connector, Web3ReactHooks, Web3ReactStore] - -const EMPTY_CONNECTOR = initializeConnector(() => EMPTY) - -export const urlAtom = atomWithDefault(() => EMPTY_CONNECTOR) -export const injectedAtom = atomWithDefault(() => EMPTY_CONNECTOR)