diff --git a/packages/api-proxy/src/common/js/utils.js b/packages/api-proxy/src/common/js/utils.js
index 44ce3bfb63..d1bf81606d 100644
--- a/packages/api-proxy/src/common/js/utils.js
+++ b/packages/api-proxy/src/common/js/utils.js
@@ -1,4 +1,5 @@
import { hasOwn, noop, getEnvObj, getFocusedNavigation } from '@mpxjs/utils'
+import { getCurrentInstance } from '@mpxjs/core'
/**
*
@@ -87,6 +88,14 @@ function failHandle (result, fail, complete) {
typeof complete === 'function' && complete(result)
}
+function getPageId () {
+ const navigation = getFocusedNavigation()
+ const currentInstance = getCurrentInstance()
+ console.log(currentInstance, currentInstance?.getPageId, navigation, navigation?.pageId)
+ const id = currentInstance?.getPageId || navigation?.pageId || null
+ return id
+}
+
const ENV_OBJ = getEnvObj()
export {
@@ -101,5 +110,6 @@ export {
defineUnsupportedProps,
successHandle,
failHandle,
- getFocusedNavigation
+ getFocusedNavigation,
+ getPageId
}
diff --git a/packages/api-proxy/src/platform/api/action-sheet/rnActionSheet.jsx b/packages/api-proxy/src/platform/api/action-sheet/rnActionSheet.jsx
index 9bb81896aa..50c8fd2fc6 100644
--- a/packages/api-proxy/src/platform/api/action-sheet/rnActionSheet.jsx
+++ b/packages/api-proxy/src/platform/api/action-sheet/rnActionSheet.jsx
@@ -1,5 +1,5 @@
import { View, Text, StyleSheet } from 'react-native'
-import { successHandle, failHandle } from '../../../common/js'
+import { successHandle, failHandle, getPageId, error } from '../../../common/js'
import Portal from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/mpx-portal/index'
import { getWindowInfo } from '../system/rnSystem'
import Animated, {
@@ -9,7 +9,16 @@ import Animated, {
} from 'react-native-reanimated'
function showActionSheet (options = {}) {
+ const id = getPageId()
const { alertText, itemList = [], itemColor = '#000000', success, fail, complete } = options
+ if (id === null) {
+ error('showActionSheet cannot be invoked outside the mpx life cycle in React Native environments')
+ const result = {
+ errMsg: 'showActionSheet:fail cannot be invoked outside the mpx life cycle in React Native environments'
+ }
+ failHandle(result, fail, complete)
+ return
+ }
if (itemList.length > 6) {
const result = {
errMsg: 'showActionSheet:fail parameter error: itemList should not be large than 6'
@@ -116,8 +125,7 @@ function showActionSheet (options = {}) {
)
}
-
- actionSheetKey = Portal.add()
+ actionSheetKey = Portal.add(, id)
}
export {
diff --git a/packages/api-proxy/src/platform/api/modal/rnModal.jsx b/packages/api-proxy/src/platform/api/modal/rnModal.jsx
index eaee365bbc..a82eb7d07a 100644
--- a/packages/api-proxy/src/platform/api/modal/rnModal.jsx
+++ b/packages/api-proxy/src/platform/api/modal/rnModal.jsx
@@ -1,8 +1,9 @@
import { View, Dimensions, Text, StyleSheet, TouchableOpacity, ScrollView, TextInput } from 'react-native'
-import { successHandle, failHandle } from '../../../common/js'
+import { successHandle, failHandle, getPageId, error } from '../../../common/js'
import Portal from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/mpx-portal/index'
const { width, height } = Dimensions.get('window')
const showModal = function (options = {}) {
+ const id = getPageId()
const {
title,
content,
@@ -17,6 +18,14 @@ const showModal = function (options = {}) {
fail,
complete
} = options
+ if (id === null) {
+ error('showModal cannot be invoked outside the mpx life cycle in React Native environments')
+ const result = {
+ errMsg: 'showModal:fail cannot be invoked outside the mpx life cycle in React Native environments'
+ }
+ failHandle(result, fail, complete)
+ return
+ }
const modalWidth = width * 0.8
const styles = StyleSheet.create({
modalTask: {
@@ -156,7 +165,7 @@ const showModal = function (options = {}) {
try {
- modalKey = Portal.add(ModalView)
+ modalKey = Portal.add(ModalView, id)
} catch (e) {
const result = {
errMsg: `showModal:fail invalid ${e}`
diff --git a/packages/api-proxy/src/platform/api/route/index.ios.js b/packages/api-proxy/src/platform/api/route/index.ios.js
index b8a0a9b93c..653f87713b 100644
--- a/packages/api-proxy/src/platform/api/route/index.ios.js
+++ b/packages/api-proxy/src/platform/api/route/index.ios.js
@@ -33,7 +33,7 @@ function resolvePath (relative, base) {
}
return stack.join('/')
}
-function isLock(navigationHelper, type, options) {
+function isLock (navigationHelper, type, options) {
if (navigationHelper.lastSuccessCallback && navigationHelper.lastFailCallback) {
const res = { errMsg: `${type}:fail the previous routing event didn't complete` }
failHandle(res, options.fail, options.complete)
@@ -48,7 +48,7 @@ function isLock(navigationHelper, type, options) {
return false
}
-function navigateTo (options = {}) {
+function navigateTo (options = {}) {
const navigationHelper = global.__navigationHelper
if (isLock(navigationHelper, 'navigateTo', options)) {
return
diff --git a/packages/api-proxy/src/platform/api/toast/rnToast.jsx b/packages/api-proxy/src/platform/api/toast/rnToast.jsx
index 6942f186d2..2909255154 100644
--- a/packages/api-proxy/src/platform/api/toast/rnToast.jsx
+++ b/packages/api-proxy/src/platform/api/toast/rnToast.jsx
@@ -1,5 +1,5 @@
import { View, Text, Image, StyleSheet, ActivityIndicator, Dimensions } from 'react-native'
-import { successHandle, failHandle } from '../../../common/js'
+import { successHandle, failHandle, getPageId, error } from '../../../common/js'
import Portal from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/mpx-portal/index'
let toastKey
@@ -55,7 +55,16 @@ const styles = StyleSheet.create({
})
function showToast (options = {}) {
+ const id = getPageId()
const { title, icon = 'success', image, duration = 1500, mask = false, success, fail, complete, isLoading } = options
+ if (id === null) {
+ error('showToast cannot be invoked outside the mpx life cycle in React Native environments')
+ const result = {
+ errMsg: 'showToast:fail cannot be invoked outside the mpx life cycle in React Native environments'
+ }
+ failHandle(result, fail, complete)
+ return
+ }
let ToastView
const successPng = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFwAAABcAgMAAACegTrLAAAADFBMVEUAAAD////R0dHj4+PcME2AAAAAAXRSTlMAQObYZgAAANNJREFUSMft1FEKwkAMBNBGyBFyH4/gR8f+ehSPLtiyQ+wM2C8Rmp+WQN90N8tOZ/1/4SbbYfpp+sBVMqafgGQKs+FvkjF8GR6aj4M8NB+GT8OX5i+GT8OX4aH5MHwZHpoPw+c3fA0xGl/zYBrP92o8vwVwF3NO8tySjXmINQLAs/WX9S8bP9UGJUZSi8MAuUqsj75payPxuWn1BmrjewCCfAvA4Fmjvx8HQL4HiJEHeRmg5k2+B8gTFeRFwL7NzREB/sCKwsG7KN2VSb7XMp31i3oBatNdEForTOoAAAAASUVORK5CYII='
const errorPng = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFwAAABcCAYAAADj79JYAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAXKADAAQAAAABAAAAXAAAAABhCMkfAAAHyUlEQVR4Ae2d74tVRRjHd7PU1IxerAX542IQQkXZDzMjN/JFSRgmJogkQS8l6c2+8a3gH2DQuyAMI2qpMMR6k6IgpoVRBL2ouGoYuRAUpJW22+dbc5e93XPmzpwzc8657jzw5dw7M+eZ5/mcc8+dmXv27NBQskQgEUgEEoFEIBFIBBKBRCARSAQSgUQgJIHhkM5i+ZqamlqA74XoJjQX6b3sMvoLXUW/Dw8P632jrXHAgXsDxJaiNeg+1EIr0Ai6GQm4JBNs6QqaQOdQG32NTqMfOQiTbBtjjQBuIK+Cykb0JFqNbkc3oiJ2jZ1+RmfRMXQEfdsE+LUCB/RiQGxCW9E6tATFsEs4PYnG0UeA/y1GJy4+awEO6OUE9xzagda6BBqwzSl8HUSHAH8+oN/muQL0IvQq+gHVbYpBsSxqHqkAEZHYKDqGmmaKaTRAis1wQTLz0Rj6BTXVFJtinN8MagWjIIGl6G00iZpuilGxakg6eEbgK9FJNGimmFfGIq5JRnAj4AdxqiHYY8Gdx3eomMdNDsF7Cz4sJNAHiPJDpNnhINs5gt/M0PHLkEkEBQ5sQdaZ/XDIIGf40gTmLXTGlD3C9kUUa8L0Ob63Al3wm2XAXoaOo1j2HY4FuMtUhlQXy5TTsq5O635DQPPQO7Eyxu819FJenqozbdhEMeU2L69/n/JQX5qv0KnWQ2KZLiUnLM5VpzaxTLkpx9JWGjhHfj1R7EFzSkeT7+APqrQMm2eqU5tYptz2mFxL9VEKOAHcQu970W2loui/c2cdPK+l1sfVJqYpx70m58L9lAJOry+jJwr37r6j1sX1a0+eqa7o2nmez6xy5aqcC1th4BxpfXPvRkGHljmZCKbtS0t1VQBXrrtN7jmh2osLA8et1rNbdvfBagXTtrCkuiqAK6EWUu6FrBBwjvCt9LYTVXF2K7EmAVfOOw0DxeZlhYDTw7OoZxLi1bNfYwFvwiWlE7VyFwNv8wbOkVXyGpdWdXYrKfVpG4WoTm2qMuW+1bDw6tMbON7vRo979RKmcb9reJhe3L2IgVh4WRHgG+kh1mKRLfh+lxTbvjHqxEAsvMwLuPkIbfDqIVxjTW7yzFaXt0+I8g2+lxUv4ER4J7o/RKQFfCyw7GOrs+xWukosxMTZfIE/imfdEVWH2aDa6mLGKhZi4my+wO/F8xxn72Eb2qDa6sJG0e1NLMTE2ZyBc63SUKjl7Dl8w4UWl7Y6y25BqlqGjZMzZ+B401mkW9TqMttZbKuLHa+YOPfvC3wkdvQW/7akbHUWl0GqxMS5fx/gWgK1TT6CRG9xYkvKVmdxGaRKTGxLx12d+ADXWNc2+ehyHOGN7Tptq4sQSpdLMXGeB/gA11lUJ/B+ayldFCp8IybOnzAf4BXmkNmVbgrtWTAzZXVe6jKDzSv0AX4ZJ3/mOaqgPO+jW/elTkzExsl8gOuX8TqB54HNOxBOAAI0EhPbHQVdXfgAv8qeMW9F6Aos441GAlnfISpzHiVk+C1bJCZi42Q+wPWxmXDyGqeRwOYBzyqPE0WvVzGJckmR0/O9/VVW0tRLipiEB84dpFM4bleGt7cjXTayxrsqq/OS0jZseiPOKPG5pGj3r9DfGX6qKBLUrOGf10wvcKBiISbO5gv8Mzz/5Ow9bEMthead4XUtGYuFmDibL/CLeA76FwHOkf63Dp/15aiyuoCLhZg4mxdwrlX6CB119h62ocDekeFSZVkHIqNp8KKjhomzYy/gxuvHbC859xCuoWLdxVR++s/6zOtdlBfJo2xkYiAWXtazNtFvb5LUDTfvouf7tY1U/wV+PzG+n2b7UKR++rn9gAbbOMP15Apn875bSR0AXX84tRl5HzDnyPIbCnBdkDtRaYg87gtbOxf9KB5m3zNyMEtNuYuBtxUCzpH9lZ4OIB3p2WbK+YBh4J17IeCml0Ns2949Dv4Oylm5F7LCwDnCF+hxP6rjLNdyqPOSaCEy2Tsp1/0m9+wWfUoLAzd+32B7ok8fIas1IngTPWOk116jBNqXMeWqnOszRizrUVXPQnmdvqZnlXqNVFaFKUf9iWQpK3uGD/HxOk4E+5BmoTFN/g/T33Q/5rVGC9NlkQKQ/30m11JdlAZuen+Nrcbm16spN+VY2oIA58jrd70xdLJ0RPkOdCnZzsd6eonWvN5O+fRlJn/3wjXKaczkWNhJZ8egM0UA3IXj99DqTgeBt5P407LCQeN3B9ttKMiJY3zO3JzlzQvA/n5mYZnXQYErEKAL9vuohWKZwMtigZbvNtoCbEEPZsEDNgFuIcLTwaLsdaS4g8c+oxvFHhz2DP/hX3KmL0cxH1iD+yimmHUL8uAZgS9F6TF6VR46gKcHRVYJvNMX4EeRHjvaNFNMo504r6stic36h/0GHxa6nCGA15eSHoGhcfRal30CtjmFL43ja3mcdS3AO/AAv5jXm5AelrAOLUEx7BJONWPUFH32PbD9/0QBrzH1KqS/XX8KafI0grx/c2UfmZZsJ5AmLZ+iIyj9SwIg9BjwtS6yDK1B96AWWoF0APRnJ3ON2Pz7I4R+iLiCBPgcaqNvkCYvF5iIxV5JpBt3q/WS4homB2EBbRci3V8o4Hov012rAq77swfi38oQZ7JEIBFIBBKBRCARSAQSgUQgEUgEEoFEICCBfwDKNlghU/F3VgAAAABJRU5ErkJggg=='
@@ -101,7 +110,7 @@ function showToast (options = {}) {
if (toastKey) {
Portal.remove(toastKey)
}
- toastKey = Portal.add(ToastView)
+ toastKey = Portal.add(ToastView, id)
if (!isLoading) {
tId = setTimeout(() => {
Portal.remove(toastKey)
diff --git a/packages/core/src/platform/patch/getDefaultOptions.ios.js b/packages/core/src/platform/patch/getDefaultOptions.ios.js
index 0189823b53..7745dc25e9 100644
--- a/packages/core/src/platform/patch/getDefaultOptions.ios.js
+++ b/packages/core/src/platform/patch/getDefaultOptions.ios.js
@@ -489,7 +489,6 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
const currentPageId = useMemo(() => ++pageId, [])
const intersectionObservers = useRef({})
usePageStatus(navigation, currentPageId)
-
useLayoutEffect(() => {
const isCustom = pageConfig.navigationStyle === 'custom'
navigation.setOptions({
@@ -566,7 +565,9 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
value: intersectionObservers.current
},
createElement(Provider,
- null,
+ {
+ pageId: currentPageId
+ },
createElement(defaultOptions,
{
navigation,
diff --git a/packages/webpack-plugin/lib/runtime/components/react/context.ts b/packages/webpack-plugin/lib/runtime/components/react/context.ts
index 0bc4d57cd9..5355012d96 100644
--- a/packages/webpack-plugin/lib/runtime/components/react/context.ts
+++ b/packages/webpack-plugin/lib/runtime/components/react/context.ts
@@ -40,7 +40,7 @@ export interface PortalManagerContextValue {
}
export interface PortalContextValue {
- mount: (children: React.ReactNode, key?: number) => number| undefined
+ mount: (children: React.ReactNode, key?: number, id?: number) => number| undefined
update: (key: number, children: React.ReactNode) => void
unmount: (key: number) => void
manager?: PortalManagerContextValue
diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-portal/index.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-portal/index.tsx
index 02a82a0d65..d8bf1354a5 100644
--- a/packages/webpack-plugin/lib/runtime/components/react/mpx-portal/index.tsx
+++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-portal/index.tsx
@@ -1,6 +1,7 @@
import { ReactNode } from 'react'
import { PortalContext, PortalContextValue } from '../context'
import PortalConsumer from './portal-consumer'
+import { useNavigation } from '@react-navigation/native'
import PortalHost, { portal } from './portal-host'
export type PortalProps = {
@@ -9,10 +10,13 @@ export type PortalProps = {
*/
children?: ReactNode
key?: string
- manager?: PortalContextValue
+ manager?: PortalContextValue,
+ pageId?: number
}
const Portal = ({ children }:PortalProps): JSX.Element => {
+ const navigation = useNavigation()
+ const pageId = navigation?.pageId
return (
{(manager) => (
diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-portal/portal-host.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-portal/portal-host.tsx
index 81134e372a..724dfca79f 100644
--- a/packages/webpack-plugin/lib/runtime/components/react/mpx-portal/portal-host.tsx
+++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-portal/portal-host.tsx
@@ -1,4 +1,4 @@
-import { useEffect, useRef, ReactNode } from 'react'
+import { useEffect, useRef, ReactNode, useMemo } from 'react'
import {
View,
DeviceEventEmitter,
@@ -11,7 +11,8 @@ import { useNavigation } from '@react-navigation/native'
import { PortalManagerContextValue, PortalContext } from '../context'
export type PortalHostProps = {
- children: ReactNode
+ children: ReactNode,
+ pageId: number
}
type addIdsMapsType = {
@@ -38,9 +39,9 @@ const styles = StyleSheet.create({
class PortalGuard {
private nextKey = 10000
- add = (e: ReactNode) => {
+ add = (e: ReactNode, id: number) => {
const key = this.nextKey++
- TopViewEventEmitter.emit(addType, e, key)
+ TopViewEventEmitter.emit(addType, e, key, id)
return key
}
@@ -57,17 +58,48 @@ class PortalGuard {
*/
export const portal = new PortalGuard()
-const PortalHost = ({ children } :PortalHostProps): JSX.Element => {
+const PortalHost = ({ children, pageId } :PortalHostProps): JSX.Element => {
+ const isMounted = useRef(false)
const _nextKey = useRef(0)
const _addType = useRef(null)
const _removeType = useRef(null)
const _updateType = useRef(null)
const manager = useRef(null)
- const focusState = useRef(false)
- const _mount = (children: ReactNode, _key?: number) => {
- if (!focusState.current) {
- return
+ const queue = useRef>([])
+ const _mount = (children: ReactNode, _key?: number, id?: number) => {
+ if (id !== pageId) return
+ const key = _key || _nextKey.current++
+ if (!isMounted.current) {
+ queue.current.push({ type: 'mount', key, children })
+ } else if (manager.current) {
+ manager.current.mount(key, children)
+ }
+ return key
+ }
+
+ const _unmount = (key: number) => {
+ if (!isMounted.current) {
+ queue.current.push({ type: 'unmount', key, children })
+ } else if (manager.current) {
+ manager.current.unmount(key)
+ }
+ }
+
+ const _update = (key: number, children?: ReactNode) => {
+ if (!isMounted.current) {
+ const operation = { type: 'mount', key, children }
+ const index = queue.current.findIndex((q) => q.key === key)
+ if (index > -1) {
+ queue.current[index] = operation
+ } else {
+ queue.current.push(operation)
+ }
+ } else if (manager.current) {
+ manager.current.update(key, children)
}
+ }
+
+ const mount = (children: ReactNode, _key?: number) => {
const key = _key || _nextKey.current++
if (manager.current) {
manager.current.mount(key, children)
@@ -75,27 +107,38 @@ const PortalHost = ({ children } :PortalHostProps): JSX.Element => {
return key
}
- const _unmount = (key: number) => {
+ const unmount = (key: number) => {
if (manager.current) {
manager.current.unmount(key)
}
}
- const _update = (key: number, children?: ReactNode, curPageId?: number) => {
+ const update = (key: number, children?: ReactNode) => {
if (manager.current) {
manager.current.update(key, children)
}
}
- const navigation = useNavigation()
- useEffect(() => {
+
+ useMemo(() => {
_addType.current = TopViewEventEmitter.addListener(addType, _mount)
_removeType.current = TopViewEventEmitter.addListener(removeType, _unmount)
_updateType.current = TopViewEventEmitter.addListener(updateType, _update)
+ }, [])
+ const navigation = useNavigation()
+ useEffect(() => {
+ while (queue.current.length && manager.current) {
+ const operation = queue.current.shift()
+ if (!operation) return
+ switch (operation.type) {
+ case 'mount':
+ manager.current.mount(operation.key, operation.children)
+ break
+ case 'unmount':
+ manager.current.unmount(operation.key)
+ }
+ }
const focusSubscription = navigation.addListener('focus', () => {
- focusState.current = true
- })
- const blurSubscription = navigation.addListener('blur', () => {
- focusState.current = false
+ isMounted.current = true
})
return () => {
@@ -103,15 +146,14 @@ const PortalHost = ({ children } :PortalHostProps): JSX.Element => {
_removeType.current?.remove()
_updateType.current?.remove()
focusSubscription()
- blurSubscription()
}
}, [])
return (