소스 검색

style: refactor fetch and context (#10795)

AkaraChen 5 달 전
부모
커밋
1cc7dc6360
7개의 변경된 파일131개의 추가작업 그리고 14개의 파일을 삭제
  1. 9 2
      web/app/(commonLayout)/datasets/Container.tsx
  2. 15 12
      web/app/(commonLayout)/layout.tsx
  3. 23 0
      web/context/query-client.tsx
  4. 2 0
      web/package.json
  5. 13 0
      web/service/use-base.ts
  6. 45 0
      web/utils/context.ts
  7. 24 0
      web/yarn.lock

+ 9 - 2
web/app/(commonLayout)/datasets/Container.tsx

@@ -5,7 +5,6 @@ import { useEffect, useMemo, useRef, useState } from 'react'
 import { useRouter } from 'next/navigation'
 import { useTranslation } from 'react-i18next'
 import { useDebounceFn } from 'ahooks'
-import useSWR from 'swr'
 
 // Components
 import ExternalAPIPanel from '../../components/datasets/external-api/external-api-panel'
@@ -28,6 +27,8 @@ import { useTabSearchParams } from '@/hooks/use-tab-searchparams'
 import { useStore as useTagStore } from '@/app/components/base/tag-management/store'
 import { useAppContext } from '@/context/app-context'
 import { useExternalApiPanel } from '@/context/external-api-panel-context'
+// eslint-disable-next-line import/order
+import { useQuery } from '@tanstack/react-query'
 
 const Container = () => {
   const { t } = useTranslation()
@@ -47,7 +48,13 @@ const Container = () => {
     defaultTab: 'dataset',
   })
   const containerRef = useRef<HTMLDivElement>(null)
-  const { data } = useSWR(activeTab === 'dataset' ? null : '/datasets/api-base-info', fetchDatasetApiBaseUrl)
+  const { data } = useQuery(
+    {
+      queryKey: ['datasetApiBaseInfo'],
+      queryFn: () => fetchDatasetApiBaseUrl('/datasets/api-base-info'),
+      enabled: activeTab !== 'dataset',
+    },
+  )
 
   const [keywords, setKeywords] = useState('')
   const [searchKeywords, setSearchKeywords] = useState('')

+ 15 - 12
web/app/(commonLayout)/layout.tsx

@@ -8,24 +8,27 @@ import Header from '@/app/components/header'
 import { EventEmitterContextProvider } from '@/context/event-emitter'
 import { ProviderContextProvider } from '@/context/provider-context'
 import { ModalContextProvider } from '@/context/modal-context'
+import { TanstackQueryIniter } from '@/context/query-client'
 
 const Layout = ({ children }: { children: ReactNode }) => {
   return (
     <>
       <GA gaType={GaType.admin} />
       <SwrInitor>
-        <AppContextProvider>
-          <EventEmitterContextProvider>
-            <ProviderContextProvider>
-              <ModalContextProvider>
-                <HeaderWrapper>
-                  <Header />
-                </HeaderWrapper>
-                {children}
-              </ModalContextProvider>
-            </ProviderContextProvider>
-          </EventEmitterContextProvider>
-        </AppContextProvider>
+        <TanstackQueryIniter>
+          <AppContextProvider>
+            <EventEmitterContextProvider>
+              <ProviderContextProvider>
+                <ModalContextProvider>
+                  <HeaderWrapper>
+                    <Header />
+                  </HeaderWrapper>
+                  {children}
+                </ModalContextProvider>
+              </ProviderContextProvider>
+            </EventEmitterContextProvider>
+          </AppContextProvider>
+        </TanstackQueryIniter>
       </SwrInitor>
     </>
   )

+ 23 - 0
web/context/query-client.tsx

@@ -0,0 +1,23 @@
+'use client'
+
+import type { FC, PropsWithChildren } from 'react'
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
+import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
+
+const STALE_TIME = 1000 * 60 * 30 // 30 minutes
+
+const client = new QueryClient({
+  defaultOptions: {
+    queries: {
+      staleTime: STALE_TIME,
+    },
+  },
+})
+
+export const TanstackQueryIniter: FC<PropsWithChildren> = (props) => {
+  const { children } = props
+  return <QueryClientProvider client={client}>
+    {children}
+    <ReactQueryDevtools initialIsOpen={false} />
+  </QueryClientProvider>
+}

+ 2 - 0
web/package.json

@@ -42,6 +42,8 @@
     "@svgdotjs/svg.js": "^3.2.4",
     "@tailwindcss/line-clamp": "^0.4.4",
     "@tailwindcss/typography": "^0.5.9",
+    "@tanstack/react-query": "^5.60.5",
+    "@tanstack/react-query-devtools": "^5.60.5",
     "ahooks": "^3.7.5",
     "class-variance-authority": "^0.7.0",
     "classnames": "^2.3.2",

+ 13 - 0
web/service/use-base.ts

@@ -0,0 +1,13 @@
+import {
+  useQueryClient,
+} from '@tanstack/react-query'
+
+export const useInvalid = (key: string[]) => {
+  const queryClient = useQueryClient()
+  return () => {
+    queryClient.invalidateQueries(
+      {
+        queryKey: key,
+      })
+  }
+}

+ 45 - 0
web/utils/context.ts

@@ -0,0 +1,45 @@
+import { type Context, type Provider, createContext, useContext } from 'react'
+import * as selector from 'use-context-selector'
+
+const createCreateCtxFunction = (
+  useContextImpl: typeof useContext,
+  createContextImpl: typeof createContext) => {
+  return function<T>({ name, defaultValue }: CreateCtxOptions<T> = {}): CreateCtxReturn<T> {
+    const emptySymbol = Symbol(`empty ${name}`)
+    // @ts-expect-error it's ok here
+    const context = createContextImpl<T>(defaultValue ?? emptySymbol)
+    const useContextValue = () => {
+      const ctx = useContextImpl(context)
+      if (ctx === emptySymbol)
+        throw new Error(`No ${name ?? 'related'} context found.`)
+
+      return ctx
+    }
+    const result = [context.Provider, useContextValue, context] as CreateCtxReturn<T>
+    result.context = context
+    result.provider = context.Provider
+    result.useContextValue = useContextValue
+    return result
+  }
+}
+
+type CreateCtxOptions<T> = {
+  defaultValue?: T
+  name?: string
+}
+
+type CreateCtxReturn<T> = [Provider<T>, () => T, Context<T>] & {
+  context: Context<T>
+  provider: Provider<T>
+  useContextValue: () => T
+}
+
+// example
+// const [AppProvider, useApp, AppContext] = createCtx<AppContextValue>()
+
+export const createCtx = createCreateCtxFunction(useContext, createContext)
+
+export const createSelectorCtx = createCreateCtxFunction(
+  selector.useContext,
+  selector.createContext as typeof createContext,
+)

+ 24 - 0
web/yarn.lock

@@ -3108,6 +3108,30 @@
     lodash.merge "^4.6.2"
     postcss-selector-parser "6.0.10"
 
+"@tanstack/query-core@5.60.5":
+  version "5.60.5"
+  resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.60.5.tgz#37b7c5ab7e6894cea9ef341299a7a3febc2ea361"
+  integrity sha512-jiS1aC3XI3BJp83ZiTuDLerTmn9P3U95r6p+6/SNauLJaYxfIC4dMuWygwnBHIZxjn2zJqEpj3nysmPieoxfPQ==
+
+"@tanstack/query-devtools@5.59.20":
+  version "5.59.20"
+  resolved "https://registry.yarnpkg.com/@tanstack/query-devtools/-/query-devtools-5.59.20.tgz#a827ac682ec1268fc9c99e7b6eb739f35b5606aa"
+  integrity sha512-vxhuQ+8VV4YWQSFxQLsuM+dnEKRY7VeRzpNabFXdhEwsBYLrjXlF1pM38A8WyKNLqZy8JjyRO8oP4Wd/oKHwuQ==
+
+"@tanstack/react-query-devtools@^5.60.5":
+  version "5.60.5"
+  resolved "https://registry.yarnpkg.com/@tanstack/react-query-devtools/-/react-query-devtools-5.60.5.tgz#fe398b4896a292fbe835d3fd4799e929de94c25a"
+  integrity sha512-lzANl0ih3CNKBGUoXhhkAAHI1Y4Yqs9Jf3iuTUsGiPpmF0RWXTeYFaQxc+h1PhJz3VwYrIYCwmPoNts0mSjSuA==
+  dependencies:
+    "@tanstack/query-devtools" "5.59.20"
+
+"@tanstack/react-query@^5.60.5":
+  version "5.60.5"
+  resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.60.5.tgz#3194c390f7eff20542b321c3042880dc3f1a81e2"
+  integrity sha512-M77bOsPwj1wYE56gk7iJvxGAr4IC12NWdIDhT+Eo8ldkWRHMvIR8I/rufIvT1OXoV/bl7EECwuRuMlxxWtvW2Q==
+  dependencies:
+    "@tanstack/query-core" "5.60.5"
+
 "@testing-library/dom@10.4.0":
   version "10.4.0"
   resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-10.4.0.tgz#82a9d9462f11d240ecadbf406607c6ceeeff43a8"