Skip to content

Commit

Permalink
refactor: add render util to support legacy and concurrent render
Browse files Browse the repository at this point in the history
  • Loading branch information
miracles1919 committed May 7, 2022
1 parent 4f1837c commit c6bdcfb
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 45 deletions.
4 changes: 2 additions & 2 deletions src/components/toast/methods.tsx
Expand Up @@ -8,7 +8,7 @@ import React, {
import { resolveContainer } from '../../utils/get-container'
import { InternalToast, ToastProps } from './toast'
import { mergeProps } from '../../utils/with-default-props'
import { reactRender, reactUnmount } from '../../utils/compatible'
import { render, unmount as reactUnmount } from '../../utils/render'

const containers = [] as HTMLDivElement[]

Expand Down Expand Up @@ -83,7 +83,7 @@ export function show(p: ToastShowProps | string) {
})

const ref = createRef<ToastShowRef>()
reactRender(<TempToast ref={ref} />, container)
render(<TempToast ref={ref} />, container)
return {
close: () => {
ref.current?.close()
Expand Down
41 changes: 0 additions & 41 deletions src/utils/compatible.ts

This file was deleted.

4 changes: 2 additions & 2 deletions src/utils/render-to-body.ts
@@ -1,5 +1,5 @@
import { ReactElement } from 'react'
import { reactRender, reactUnmount } from './compatible'
import { render, unmount as reactUnmount } from './render'

export function renderToBody(element: ReactElement) {
const container = document.createElement('div')
Expand All @@ -10,6 +10,6 @@ export function renderToBody(element: ReactElement) {
container.parentNode.removeChild(container)
}
}
reactRender(element, container)
render(element, container)
return unmount
}
73 changes: 73 additions & 0 deletions src/utils/render.ts
@@ -0,0 +1,73 @@
import { ReactElement } from 'react'
// import { render, unmountComponentAtNode, } from 'react-dom'
import * as ReactDOM from 'react-dom'
import type { Root } from 'react-dom/client'

// 移植自rc-util: https://github.com/react-component/util/blob/master/src/React/render.ts

type CreateRoot = (container: ContainerType) => Root

// Let compiler not to search module usage
const fullClone = {
...ReactDOM,
} as typeof ReactDOM & {
createRoot?: CreateRoot
}

const { version, render: reactRender, unmountComponentAtNode } = fullClone

let createRoot: CreateRoot
try {
const mainVersion = Number((version || '').split('.')[0])
if (mainVersion >= 18 && fullClone.createRoot) {
createRoot = fullClone.createRoot
}
} catch (e) {
// Do nothing;
}

const MARK = '__antd_mobile_root__'

// ========================== Render ==========================
type ContainerType = (Element | DocumentFragment) & {
[MARK]?: Root
}

function legacyRender(node: ReactElement, container: ContainerType) {
reactRender(node, container)
}

function concurrentRender(node: ReactElement, container: ContainerType) {
const root = container[MARK] || createRoot(container)
root.render(node)
container[MARK] = root
}

export function render(node: ReactElement, container: ContainerType) {
if (createRoot as unknown) {
concurrentRender(node, container)
return
}
legacyRender(node, container)
}

// ========================== Unmount =========================
function legacyUnmount(container: ContainerType) {
return unmountComponentAtNode(container)
}

async function concurrentUnmount(container: ContainerType) {
// Delay to unmount to avoid React 18 sync warning
return Promise.resolve().then(() => {
container[MARK]?.unmount()
delete container[MARK]
})
}

export function unmount(container: ContainerType) {
if (createRoot as unknown) {
return concurrentUnmount(container)
}

return legacyUnmount(container)
}

0 comments on commit c6bdcfb

Please sign in to comment.