refactor: use suspense in AppDefender (#1020)
This commit is contained in:
@@ -16,14 +16,13 @@ import { ModalProvider } from '@/store/globalModal';
|
|||||||
// import AppStateProvider2 from '@/providers/app-state-provider2/provider';
|
// import AppStateProvider2 from '@/providers/app-state-provider2/provider';
|
||||||
|
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { useEffect } from 'react';
|
import { Suspense, useEffect } from 'react';
|
||||||
import { useAppState } from '@/providers/app-state-provider';
|
|
||||||
import { PageLoading } from '@/components/loading';
|
import { PageLoading } from '@/components/loading';
|
||||||
import Head from 'next/head';
|
import Head from 'next/head';
|
||||||
import '@affine/i18n';
|
import '@affine/i18n';
|
||||||
import { useTranslation } from '@affine/i18n';
|
import { useTranslation } from '@affine/i18n';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { GlobalAppProvider } from '@/store/app';
|
import { DataCenterLoader, GlobalAppProvider } from '@/store/app';
|
||||||
|
|
||||||
const ThemeProvider = dynamic(() => import('@/providers/ThemeProvider'), {
|
const ThemeProvider = dynamic(() => import('@/providers/ThemeProvider'), {
|
||||||
ssr: false,
|
ssr: false,
|
||||||
@@ -80,7 +79,13 @@ const App = ({ Component, pageProps }: AppPropsWithLayout) => {
|
|||||||
{NoNeedAppStatePageList.includes(router.route) ? (
|
{NoNeedAppStatePageList.includes(router.route) ? (
|
||||||
getLayout(<Component {...pageProps} />)
|
getLayout(<Component {...pageProps} />)
|
||||||
) : (
|
) : (
|
||||||
<AppDefender>{getLayout(<Component {...pageProps} />)}</AppDefender>
|
<Suspense fallback={<PageLoading />}>
|
||||||
|
{/* we should put this before every component in case of they read a null value */}
|
||||||
|
<DataCenterLoader />
|
||||||
|
<AppDefender>
|
||||||
|
{getLayout(<Component {...pageProps} />)}
|
||||||
|
</AppDefender>
|
||||||
|
</Suspense>
|
||||||
)}
|
)}
|
||||||
</ProviderComposer>
|
</ProviderComposer>
|
||||||
</GlobalAppProvider>
|
</GlobalAppProvider>
|
||||||
@@ -90,15 +95,13 @@ const App = ({ Component, pageProps }: AppPropsWithLayout) => {
|
|||||||
|
|
||||||
const AppDefender = ({ children }: PropsWithChildren) => {
|
const AppDefender = ({ children }: PropsWithChildren) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { synced } = useAppState();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (['/index.html', '/'].includes(router.asPath)) {
|
if (['/index.html', '/'].includes(router.asPath)) {
|
||||||
router.replace('/workspace');
|
router.replace('/workspace');
|
||||||
}
|
}
|
||||||
}, [router]);
|
}, [router]);
|
||||||
|
|
||||||
return <div>{synced ? children : <PageLoading />}</div>;
|
return <>{children}</>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|||||||
@@ -45,21 +45,14 @@ export const AppStateProvider = ({
|
|||||||
|
|
||||||
const onceRef = useRef(true);
|
const onceRef = useRef(true);
|
||||||
const dataCenter = useGlobalState(store => store.dataCenter);
|
const dataCenter = useGlobalState(store => store.dataCenter);
|
||||||
useEffect(() => {
|
if (onceRef.current && dataCenter) {
|
||||||
if (dataCenter !== null) {
|
setAppState({
|
||||||
if (onceRef.current) {
|
workspaceList: dataCenter.workspaces,
|
||||||
setAppState({
|
currentWorkspace: null,
|
||||||
workspaceList: dataCenter.workspaces,
|
pageList: [],
|
||||||
currentWorkspace: null,
|
});
|
||||||
pageList: [],
|
onceRef.current = false;
|
||||||
synced: true,
|
}
|
||||||
});
|
|
||||||
onceRef.current = false;
|
|
||||||
} else {
|
|
||||||
console.warn('dataCenter Effect called twice. Please fix this ASAP');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [dataCenter]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// FIXME: onWorkspacesChange should have dispose function
|
// FIXME: onWorkspacesChange should have dispose function
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ export type AppStateValue = {
|
|||||||
workspaceList: WorkspaceUnit[];
|
workspaceList: WorkspaceUnit[];
|
||||||
currentWorkspace: WorkspaceUnit | null;
|
currentWorkspace: WorkspaceUnit | null;
|
||||||
pageList: PageMeta[];
|
pageList: PageMeta[];
|
||||||
synced: boolean;
|
|
||||||
blobDataSynced?: boolean;
|
blobDataSynced?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
import { createContext, useContext, useEffect, useMemo, useRef } from 'react';
|
import { createContext, useContext, useMemo } from 'react';
|
||||||
import { createStore, StateCreator, useStore } from 'zustand';
|
import { createStore, StateCreator, useStore } from 'zustand';
|
||||||
import { combine, subscribeWithSelector } from 'zustand/middleware';
|
import { combine, subscribeWithSelector } from 'zustand/middleware';
|
||||||
import type { UseBoundStore } from 'zustand/react';
|
import type { UseBoundStore } from 'zustand/react';
|
||||||
@@ -27,6 +27,7 @@ export type GlobalActionsCreator<Actions, Store = GlobalState> = StateCreator<
|
|||||||
|
|
||||||
export interface GlobalState extends BlockSuiteState, UserState {
|
export interface GlobalState extends BlockSuiteState, UserState {
|
||||||
readonly dataCenter: DataCenter;
|
readonly dataCenter: DataCenter;
|
||||||
|
readonly dataCenterPromise: Promise<DataCenter>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GlobalActions extends BlockSuiteActions, UserActions {}
|
export interface GlobalActions extends BlockSuiteActions, UserActions {}
|
||||||
@@ -40,6 +41,8 @@ const create = () =>
|
|||||||
...createUserState(),
|
...createUserState(),
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
dataCenter: null!,
|
dataCenter: null!,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
dataCenterPromise: null!,
|
||||||
},
|
},
|
||||||
/* deepscan-disable TOO_MANY_ARGS */
|
/* deepscan-disable TOO_MANY_ARGS */
|
||||||
(set, get, api) => ({
|
(set, get, api) => ({
|
||||||
@@ -71,27 +74,25 @@ export const useGlobalState: UseBoundStore<Store> = ((
|
|||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
}) as any;
|
}) as any;
|
||||||
|
|
||||||
function DataCenterSideEffect() {
|
export function DataCenterLoader() {
|
||||||
const onceRef = useRef(true);
|
const dataCenter = useGlobalState(store => store.dataCenter);
|
||||||
|
const dataCenterPromise = useGlobalState(store => store.dataCenterPromise);
|
||||||
const api = useGlobalStateApi();
|
const api = useGlobalStateApi();
|
||||||
useEffect(() => {
|
if (!dataCenter && !dataCenterPromise) {
|
||||||
async function init() {
|
const promise = getDataCenter();
|
||||||
const dataCenterPromise = getDataCenter();
|
api.setState({ dataCenterPromise: promise });
|
||||||
dataCenterPromise.then(async dataCenter => {
|
promise.then(async dataCenter => {
|
||||||
// Ensure datacenter has at least one workspace
|
// Ensure datacenter has at least one workspace
|
||||||
if (dataCenter.workspaces.length === 0) {
|
if (dataCenter.workspaces.length === 0) {
|
||||||
await createDefaultWorkspace(dataCenter);
|
await createDefaultWorkspace(dataCenter);
|
||||||
}
|
}
|
||||||
api.setState({ dataCenter });
|
api.setState({ dataCenter });
|
||||||
});
|
});
|
||||||
}
|
throw promise;
|
||||||
if (onceRef.current) {
|
}
|
||||||
onceRef.current = false;
|
if (!dataCenter) {
|
||||||
init().then(() => {
|
throw dataCenterPromise;
|
||||||
console.log('datacenter init success');
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [api]);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +100,6 @@ export const GlobalAppProvider: React.FC<React.PropsWithChildren> =
|
|||||||
function ModelProvider({ children }) {
|
function ModelProvider({ children }) {
|
||||||
return (
|
return (
|
||||||
<GlobalStateContext.Provider value={useMemo(() => create(), [])}>
|
<GlobalStateContext.Provider value={useMemo(() => create(), [])}>
|
||||||
<DataCenterSideEffect />
|
|
||||||
{children}
|
{children}
|
||||||
</GlobalStateContext.Provider>
|
</GlobalStateContext.Provider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -29,8 +29,9 @@ export const createWorkspaceUnit = async (params: WorkspaceUnitCtorParams) => {
|
|||||||
await setDefaultAvatar(blocksuiteWorkspace);
|
await setDefaultAvatar(blocksuiteWorkspace);
|
||||||
workspaceUnit.update({ avatar: blocksuiteWorkspace.meta.avatar });
|
workspaceUnit.update({ avatar: blocksuiteWorkspace.meta.avatar });
|
||||||
}
|
}
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
await writeUpdatesToLocal(blocksuiteWorkspace);
|
await writeUpdatesToLocal(blocksuiteWorkspace);
|
||||||
|
}
|
||||||
|
|
||||||
workspaceUnit.setBlocksuiteWorkspace(blocksuiteWorkspace);
|
workspaceUnit.setBlocksuiteWorkspace(blocksuiteWorkspace);
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export const createBlocksuiteWorkspace = (
|
|||||||
return new BlocksuiteWorkspace({
|
return new BlocksuiteWorkspace({
|
||||||
room: workspaceId,
|
room: workspaceId,
|
||||||
defaultFlags: { enable_slash_menu: true },
|
defaultFlags: { enable_slash_menu: true },
|
||||||
|
isSSR: typeof window === 'undefined',
|
||||||
...workspaceOption,
|
...workspaceOption,
|
||||||
})
|
})
|
||||||
.register(builtInSchemas)
|
.register(builtInSchemas)
|
||||||
|
|||||||
Reference in New Issue
Block a user