Skip to content

Commit b886c4a

Browse files
committed
refactor: provider composer
Signed-off-by: Innei <[email protected]>
1 parent 999da6b commit b886c4a

File tree

14 files changed

+87
-62
lines changed

14 files changed

+87
-62
lines changed

src/components/app/Composer/index.tsx

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import type { FC, PropsWithChildren, ReactNode } from 'react'
2+
import { cloneElement } from 'react'
3+
4+
// @copy https://github.dev/toeverything/AFFiNE/blob/fd510834ed45a4e8bed9ded95cbe5ee284334236/apps/web/src/components/provider-composer.tsx#L1
5+
export const ProviderComposer: FC<
6+
PropsWithChildren<{
7+
contexts: any
8+
}>
9+
> = ({ contexts, children }) =>
10+
contexts.reduceRight(
11+
(kids: ReactNode, parent: any) =>
12+
cloneElement(parent, {
13+
children: kids,
14+
}),
15+
children,
16+
)

src/components/app/ErrorBoundary/index.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import Router from 'next/router'
22
import React, { PureComponent, createElement } from 'react'
33

44
export class ErrorBoundary extends PureComponent<{
5-
children: React.ReactNode
5+
children?: React.ReactNode
66
fallbackComponent?: React.ComponentType<any>
77
[k: string]: any
88
}> {

src/components/layouts/AppLayout.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { loadStyleSheet } from '~/utils/load-script'
2020

2121
import { useStore } from '../../store'
2222

23-
export const Content: FC = observer((props) => {
23+
export const AppLayout: FC = observer((props) => {
2424
const { userStore: master } = useStore()
2525

2626
useScreenMedia()

src/components/layouts/BasicLayout/index.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ import {
1717
} from '@mx-space/kami-design/components/Icons/layout'
1818

1919
import { TrackerAction } from '~/constants/tracker'
20-
import { useRootStore } from '~/context'
2120
import { useAnalyze } from '~/hooks/use-analyze'
2221
import { useThemeBackground } from '~/hooks/use-kami'
2322
import { useMediaToggle } from '~/hooks/use-media-toggle'
23+
import { useRootStore } from '~/provider'
2424
import { springScrollToElement } from '~/utils/spring'
2525

2626
const Header = React.lazy(() =>

src/hooks/use-initial-data.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useContext } from 'react'
22

3-
import { InitialContext } from '~/context/initial-data'
3+
import { InitialContext } from '~/provider/initial-data'
44

55
export const useInitialData = () => {
66
return useContext(InitialContext).aggregateData

src/pages/_app.tsx

+31-53
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,24 @@ import 'windi.css'
22
import 'assets/styles/main.css'
33
import '../../third/qp/index.css'
44

5-
import NextApp from 'next/app'
65
import type { AppContext } from 'next/app'
6+
import NextApp from 'next/app'
77
import { useRouter } from 'next/router'
88
import type { FC } from 'react'
9-
import React, { memo, useMemo, useRef } from 'react'
10-
import type { ToastContainerProps } from 'react-toastify'
11-
import { ToastContainer } from 'react-toastify'
12-
import { SWRConfig } from 'swr'
13-
import type { FullConfiguration } from 'swr/_internal'
9+
import { useMemo } from 'react'
1410

11+
import { ProviderComposer } from '~/components/app/Composer'
1512
import { NoDataErrorView } from '~/components/app/Error/no-data'
1613
import { ErrorBoundary } from '~/components/app/ErrorBoundary'
1714
import { BasicLayout } from '~/components/layouts/BasicLayout'
1815
import { DebugLayout } from '~/components/layouts/DebugLayout'
19-
import type { InitialDataType } from '~/context/initial-data'
20-
import { InitialContextProvider } from '~/context/initial-data'
21-
import { RootStoreProvider } from '~/context/root-store'
16+
import type { InitialDataType } from '~/provider/initial-data'
17+
import { InitialContextProvider } from '~/provider/initial-data'
18+
import { RootStoreProvider } from '~/provider/root-store'
19+
import { SWRProvider } from '~/provider/swr'
2220
import { isDev } from '~/utils/env'
23-
import { localStorageProvider } from '~/utils/swr'
2421

25-
import { Content } from '../components/layouts/AppLayout'
22+
import { AppLayout } from '../components/layouts/AppLayout'
2623
import { attachRequestProxy, fetchInitialData } from '../utils/app'
2724

2825
interface DataModel {
@@ -35,12 +32,31 @@ const App: FC<DataModel & { Component: any; pageProps: any; err: any }> = (
3532

3633
const router = useRouter()
3734

35+
const PageProviders = useMemo(
36+
() => [
37+
<SWRProvider key="SWRProvider" />,
38+
<ErrorBoundary key="ErrorBoundary1" />,
39+
<BasicLayout key="BasicLayout" />,
40+
<AppLayout key="appLayout" />,
41+
<ErrorBoundary key="ErrorBoundary2" />,
42+
],
43+
[],
44+
)
45+
46+
const AppProviders = useMemo(
47+
() => [
48+
<RootStoreProvider key="RootStoreProvider" />,
49+
<InitialContextProvider value={initData} key="InitialContextProvider" />,
50+
],
51+
[initData],
52+
)
53+
3854
const Inner = useMemo(() => {
3955
// 兜底页
4056
return initData.aggregateData ? (
41-
<Wrapper>
57+
<ProviderComposer contexts={PageProviders}>
4258
<Component {...pageProps} />
43-
</Wrapper>
59+
</ProviderComposer>
4460
) : (
4561
<NoDataErrorView />
4662
)
@@ -54,47 +70,8 @@ const App: FC<DataModel & { Component: any; pageProps: any; err: any }> = (
5470
</RootStoreProvider>
5571
)
5672
}
57-
return (
58-
<RootStoreProvider>
59-
<InitialContextProvider value={initData}>{Inner}</InitialContextProvider>
60-
</RootStoreProvider>
61-
)
73+
return <ProviderComposer contexts={AppProviders}>{Inner}</ProviderComposer>
6274
}
63-
const Wrapper = memo((props) => {
64-
const toastOptions = useRef<ToastContainerProps>({
65-
autoClose: 3000,
66-
pauseOnHover: true,
67-
hideProgressBar: true,
68-
newestOnTop: true,
69-
closeOnClick: true,
70-
closeButton: false,
71-
toastClassName: () => '',
72-
bodyClassName: () => '',
73-
})
74-
const swrConfig = useRef<
75-
Partial<FullConfiguration> & {
76-
provider?: any
77-
}
78-
>({
79-
refreshInterval: 30_000,
80-
provider: localStorageProvider,
81-
})
82-
return (
83-
<>
84-
<SWRConfig value={swrConfig.current}>
85-
<ErrorBoundary>
86-
<BasicLayout>
87-
<Content>
88-
<ErrorBoundary>{props.children}</ErrorBoundary>
89-
</Content>
90-
</BasicLayout>
91-
</ErrorBoundary>
92-
</SWRConfig>
93-
94-
<ToastContainer {...toastOptions.current} />
95-
</>
96-
)
97-
})
9875
// @ts-ignore
9976
App.getInitialProps = async (props: AppContext) => {
10077
const ctx = props.ctx
@@ -109,6 +86,7 @@ App.getInitialProps = async (props: AppContext) => {
10986
return await NextApp.getInitialProps(props)
11087
} catch (e) {
11188
// TODO next rfc Layout, 出了就重构这里
89+
// 2023 tmd next rfc 全是大饼,根本没法用
11290
// 只有无数据 也就是 服务端不跑起来 或者接口不对的时候 捕获异常
11391
// 这是为什么呢 说来说去还是 nextjs 太辣鸡了 只能各种 hack
11492
// 只能这样了
File renamed without changes.
File renamed without changes.

src/context/root-store.tsx src/provider/root-store.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export function useRootStore() {
2626
return context
2727
}
2828
export const store = initializeStore()
29-
export function RootStoreProvider({ children }: { children: ReactNode }) {
29+
export function RootStoreProvider({ children }: { children?: ReactNode }) {
3030
if (isDev && isClientSide() && !window.store) {
3131
Object.defineProperty(window, 'store', {
3232
get() {

src/utils/swr.ts src/provider/swr.tsx

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,18 @@
1-
import { isClientSide } from './env'
1+
import type { FC } from 'react'
2+
import { SWRConfig } from 'swr'
3+
import type { FullConfiguration, ProviderConfiguration } from 'swr/_internal'
4+
5+
import { isClientSide } from '~/utils/env'
6+
7+
const swrConfig = {
8+
refreshInterval: 30_000,
9+
// @ts-ignore
10+
provider: localStorageProvider,
11+
} satisfies FullConfiguration & ProviderConfiguration
12+
13+
export const SWRProvider: FC<{ children?: JSX.Element }> = ({ children }) => {
14+
return <SWRConfig value={swrConfig}>{children}</SWRConfig>
15+
}
216

317
export function localStorageProvider() {
418
if (!isClientSide()) {

src/provider/toastify.tsx

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import type { ToastContainerProps } from 'react-toastify'
2+
import { ToastContainer as _ToastContainer } from 'react-toastify'
3+
4+
const toastOptions = {
5+
autoClose: 3000,
6+
pauseOnHover: true,
7+
hideProgressBar: true,
8+
newestOnTop: true,
9+
closeOnClick: true,
10+
closeButton: false,
11+
toastClassName: () => '',
12+
bodyClassName: () => '',
13+
} satisfies ToastContainerProps
14+
15+
export const ToastContainer = () => {
16+
return <_ToastContainer {...toastOptions} />
17+
}

src/store/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { store, useRootStore } from '~/context/root-store'
1+
import { store, useRootStore } from '~/provider/root-store'
22

33
export const useStore = useRootStore
44
export * from './root-store'

src/utils/app.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { TokenKey } from '~/utils/cookie'
1010
import { isClientSide, isServerSide } from '~/utils/env'
1111

1212
import PKG from '../../package.json'
13-
import type { InitialDataType } from '../context'
13+
import type { InitialDataType } from '../provider'
1414

1515
export const attachRequestProxy = (request?: IncomingMessage) => {
1616
if (!request) {

types.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { FC } from 'react'
22

3-
import type { InitialDataType } from '~/context/initial-data'
3+
import type { InitialDataType } from '~/provider/initial-data'
44

55
import 'react-dom/next'
66

0 commit comments

Comments
 (0)