Skip to content

Commit

Permalink
removed duplicate query
Browse files Browse the repository at this point in the history
  • Loading branch information
NoahSaso committed Jun 6, 2024
1 parent 57e7496 commit b7764ac
Show file tree
Hide file tree
Showing 17 changed files with 174 additions and 143 deletions.
14 changes: 5 additions & 9 deletions apps/dapp/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { DefaultSeo } from 'next-seo'
import type { AppProps } from 'next/app'
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import { RecoilRoot, useRecoilState, useSetRecoilState } from 'recoil'
import { useRecoilState, useSetRecoilState } from 'recoil'

import {
activeThemeAtom,
Expand All @@ -21,7 +21,7 @@ import {
import {
AppContextProvider,
DappLayout,
ReactQueryClientProvider,
StateProvider,
WalletProvider,
} from '@dao-dao/stateful'
import {
Expand Down Expand Up @@ -168,13 +168,9 @@ const DApp = (props: AppProps) => (
}}
/>

<ReactQueryClientProvider
dehyratedState={props.pageProps.reactQueryDehydratedState}
>
<RecoilRoot>
<InnerApp {...props} />
</RecoilRoot>
</ReactQueryClientProvider>
<StateProvider dehyratedState={props.pageProps.reactQueryDehydratedState}>
<InnerApp {...props} />
</StateProvider>
</>
)

Expand Down
16 changes: 6 additions & 10 deletions apps/sda/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import PlausibleProvider from 'next-plausible'
import { DefaultSeo } from 'next-seo'
import type { AppProps } from 'next/app'
import { useRouter } from 'next/router'
import { Fragment, useEffect, useState } from 'react'
import { RecoilRoot, useRecoilState, useSetRecoilState } from 'recoil'
import { useEffect, useState } from 'react'
import { useRecoilState, useSetRecoilState } from 'recoil'

import {
activeThemeAtom,
Expand All @@ -22,8 +22,8 @@ import {
AppContextProvider,
DaoPageWrapper,
DaoPageWrapperProps,
ReactQueryClientProvider,
SdaLayout,
StateProvider,
WalletProvider,
} from '@dao-dao/stateful'
import {
Expand Down Expand Up @@ -182,13 +182,9 @@ const Sda = (props: AppProps<DaoPageWrapperProps>) => {
}}
/>

<ReactQueryClientProvider
dehyratedState={props.pageProps.reactQueryDehydratedState}
>
<RecoilRoot>
<InnerApp setIcon={setIcon} {...props} />
</RecoilRoot>
</ReactQueryClientProvider>
<StateProvider dehyratedState={props.pageProps.reactQueryDehydratedState}>
<InnerApp setIcon={setIcon} {...props} />
</StateProvider>
</>
)
}
Expand Down
28 changes: 25 additions & 3 deletions packages/state/query/client.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
import { QueryClient, QueryKey, dehydrate } from '@tanstack/react-query'
import {
DehydratedState,
QueryClient,
QueryKey,
dehydrate,
hydrate,
} from '@tanstack/react-query'

export const makeReactQueryClient = () =>
new QueryClient({
/**
* Make a new instance of the react query client.
*/
export const makeReactQueryClient = (
/**
* Optionally hydrate the query client with dehydrated state.
*/
dehydratedState?: DehydratedState
) => {
const client = new QueryClient({
defaultOptions: {
queries: {
// Global default to 60 seconds.
Expand All @@ -10,6 +24,14 @@ export const makeReactQueryClient = () =>
},
})

// Hydate if dehydrated state is provided.
if (dehydratedState) {
hydrate(client, dehydratedState)
}

return client
}

/**
* Dehydrate query client and remove undefined values so it can be serialized.
*/
Expand Down
3 changes: 1 addition & 2 deletions packages/state/query/queries/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@ import {
import { chainQueries } from './chain'
import { indexerQueries } from './indexer'

// TODO(rq): export this and replace the other util with it
/**
* Fetch contract info stored in state, which contains its name and version.
*/
const fetchContractInfo = async (
export const fetchContractInfo = async (
queryClient: QueryClient,
{
chainId,
Expand Down
7 changes: 7 additions & 0 deletions packages/state/recoil/atoms/misc.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { QueryClient } from '@tanstack/react-query'
import { atom } from 'recoil'

import { PageHeaderProps, Web3AuthPrompt } from '@dao-dao/types'
Expand Down Expand Up @@ -62,3 +63,9 @@ export const pageHeaderPropsAtom = atom<PageHeaderProps>({
key: 'pageHeaderProps',
default: {},
})

// Store query client in Recoil atom so it's accessible from Recoil selectors
// while we migrate from Recoil to React Query.
export const queryClientAtom = atom<QueryClient>({
key: 'queryClient',
})
84 changes: 21 additions & 63 deletions packages/state/utils/contract.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import { fromUtf8, toUtf8 } from '@cosmjs/encoding'
import { QueryClient } from '@tanstack/react-query'

import {
ContractVersionInfo,
PreProposeModule,
PreProposeModuleType,
PreProposeModuleTypedConfig,
} from '@dao-dao/types'
import { Config as NeutronCwdSubdaoTimelockSingleConfig } from '@dao-dao/types/contracts/NeutronCwdSubdaoTimelockSingle'
import {
ContractName,
INVALID_CONTRACT_ERROR_SUBSTRINGS,
cosmWasmClientRouter,
getRpcForChainId,
parseContractVersion,
Expand All @@ -22,69 +20,20 @@ import {
NeutronCwdSubdaoTimelockSingleQueryClient,
} from '../contracts'
import { queryIndexer } from '../indexer'

export const fetchContractInfo = async (
chainId: string,
contractAddress: string
): Promise<ContractVersionInfo | undefined> => {
let info: ContractVersionInfo | undefined

// Try indexer first.
try {
info = await queryIndexer({
type: 'contract',
address: contractAddress,
formula: 'info',
chainId,
})
} catch (err) {
// Ignore error.
console.error(err)
}

// If indexer fails, fallback to querying chain.
if (!info) {
try {
const client = await cosmWasmClientRouter.connect(
getRpcForChainId(chainId)
)
const { data: contractInfo } = await client[
'forceGetQueryClient'
]().wasm.queryContractRaw(contractAddress, toUtf8('contract_info'))
if (contractInfo) {
info = JSON.parse(fromUtf8(contractInfo))
}
} catch (err) {
if (
err instanceof Error &&
INVALID_CONTRACT_ERROR_SUBSTRINGS.some((substring) =>
(err as Error).message.includes(substring)
)
) {
// Ignore error.
console.error(err)
return undefined
}

// Rethrow other errors because it should not have failed.
throw err
}
}

return info
}
import { contractQueries } from '../query'

export const fetchPreProposeModule = async (
queryClient: QueryClient,
chainId: string,
preProposeAddress: string
): Promise<PreProposeModule> => {
const contractInfo = await fetchContractInfo(chainId, preProposeAddress)
const contractVersion =
contractInfo && parseContractVersion(contractInfo.version)

if (!contractInfo || !contractVersion) {
throw new Error('Failed to fetch pre propose module info')
}
const { info: contractInfo } = await queryClient.fetchQuery(
contractQueries.info(queryClient, {
chainId,
address: preProposeAddress,
})
)
const contractVersion = parseContractVersion(contractInfo.version)

let typedConfig: PreProposeModuleTypedConfig = {
type: PreProposeModuleType.Other,
Expand Down Expand Up @@ -122,8 +71,17 @@ export const fetchPreProposeModule = async (
}

// Check if approver is an approver contract.
const approverContractInfo = await fetchContractInfo(chainId, approver)
if (approverContractInfo?.contract === ContractName.PreProposeApprover) {
const approverContractName = (
await queryClient
.fetchQuery(
contractQueries.info(queryClient, {
chainId,
address: approver,
})
)
.catch(() => undefined)
)?.info.contract
if (approverContractName === ContractName.PreProposeApprover) {
preProposeApproverContract = approver
approver = undefined

Expand Down
36 changes: 0 additions & 36 deletions packages/stateful/components/ReactQueryClientProvider.tsx

This file was deleted.

59 changes: 59 additions & 0 deletions packages/stateful/components/StateProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import {
DehydratedState,
QueryClientProvider,
useQueryClient,
} from '@tanstack/react-query'
import { ReactNode, useEffect, useMemo } from 'react'
import { RecoilRoot, useSetRecoilState } from 'recoil'

import { makeReactQueryClient, queryClientAtom } from '@dao-dao/state'

export type StateProviderProps = {
/**
* Children to render.
*/
children: ReactNode
/**
* Optional dehyrated state from a react-query client instance on the server
* to initialize data.
*/
dehyratedState?: DehydratedState
}

/**
* A provider that wraps an app with the state providers, like React Query and
* Recoil.
*/
export const StateProvider = ({
children,
dehyratedState,
}: StateProviderProps) => {
const client = useMemo(
() => makeReactQueryClient(dehyratedState),
[dehyratedState]
)

return (
<QueryClientProvider client={client}>
<RecoilRoot
initializeState={
// Give query client to Recoil so selectors can access queries.
({ set }) => set(queryClientAtom, client)
}
>
<InnerStateProvider>{children}</InnerStateProvider>
</RecoilRoot>
</QueryClientProvider>
)
}

const InnerStateProvider = ({ children }: { children: ReactNode }) => {
const queryClient = useQueryClient()
const setQueryClient = useSetRecoilState(queryClientAtom)
// Update Recoil atom when the query client changes.
useEffect(() => {
setQueryClient(queryClient)
}, [queryClient, setQueryClient])

return <>{children} </>
}
Loading

0 comments on commit b7764ac

Please sign in to comment.