import React , { useCallback , useEffect , useState } from "react" ; import ReactDOM from "react-dom" ; import { createBrowserHistory , createHashHistory , createMemoryHistory , History } from "history" ; import { Container , ContainerProps } from "../Container" ; import { ContextValue , setContextValue } from "../context" ; import pick from "lodash/pick" ; export type RouteMethod = "browser" | "hash" | "memory" ; export type AwaitValue < T > = T | Promise < T > ; export interface CreateAppOption extends Omit < ContainerProps , "children" > , ContextValue { onBeforeRenderPage ? : ( pathname ? : string ) => AwaitValue < void > ; onAfterRenderPage ? : ( pathname ? : string ) => AwaitValue < void > ; renderLoading ? : ( pathname ? : string ) => AwaitValue < React . ReactNode > ; renderPage ? : ( pathname ? : string ) => AwaitValue < React . ReactNode > ; routeMethod ? : RouteMethod ; defaultRoute ? : string ; target : string | HTMLElement ; } export let history = null ; export function getHistory ( routeMethod = "browser" ) { if ( history === null ) { const createMap = { browser : createBrowserHistory , hash : createHashHistory , memory : createMemoryHistory , } ; history = createMap [ routeMethod ] ( ) ; } return history ; } param option export async function createApp ( option ) { if ( ! option . routeMethod || [ "browser" , "hash" , "memory" ] . indexOf ( option . routeMethod ) === - 1 ) { option . routeMethod = "browser" ; } if ( ! option . defaultRoute ) { option . defaultRoute = "/index" ; } history = getHistory ( option . routeMethod ) ; const context = pick ( option , [ "minDocWidth" , "maxDocWidth" ] ) ; const containerProps = pick ( option , [ "designWidth" , "globalStyle" ] ) ; const { onBeforeRenderPage , onAfterRenderPage , renderLoading , renderPage } = option ; setContextValue ( context ) ; returns const App = ( ) => { const [ page , setPage ] = useState < React . ReactNode | null > ( null ) ; /**
         * 渲染一个新页面
         */ const showPage = useCallback ( async ( pathname ) => { const pathReg = /^\/*|\/*$/g ; pathname = pathname . replace ( pathReg , "" ) ; if ( ! pathname ) { pathname = option . defaultRoute ! . replace ( pathReg , "" ) ; } if ( typeof renderLoading === "function" ) { setPage ( renderLoading ?. ( pathname ) ) ; } await onBeforeRenderPage ?. ( pathname ) ; setPage ( await renderPage ?. ( pathname ) ) ; await onAfterRenderPage ?. ( ) ; } , [ ] ) ; /**
         * 监听变化
         */ useEffect ( ( ) => { const unlisten = history ! . listen ( ( { location } ) => { showPage ( location . pathname ) ; } ) ; showPage ( history ! . location . pathname ) ; return unlisten ; } , [ ] ) ; return < Container { ... containerProps } > { page } < /Container>; } ; let mount = null ; if ( typeof option . target === "string" ) { mount = document . querySelector ( option . target ) ; } else if ( option . target instanceof HTMLElement ) { mount = option . target ; } await new Promise < void > ( ( resolve ) => { ReactDOM . render ( < App />, mount, resolve); } ) ; }