From 440983710104f0629d2f06cec19789a9932ae419 Mon Sep 17 00:00:00 2001 From: wangshunnn Date: Wed, 25 Dec 2024 15:38:48 +0800 Subject: [PATCH 01/10] feat: resolve parent component for provide/inject --- packages/core/src/core/proxy.js | 19 ++++++----- packages/core/src/platform/export/inject.js | 35 ++++++++------------- 2 files changed, 22 insertions(+), 32 deletions(-) diff --git a/packages/core/src/core/proxy.js b/packages/core/src/core/proxy.js index 54d4603f55..b4c56db78d 100644 --- a/packages/core/src/core/proxy.js +++ b/packages/core/src/core/proxy.js @@ -118,6 +118,8 @@ export default class MpxProxy { // 收集setup中动态注册的hooks,小程序与web环境都需要 this.hooks = {} if (!isWeb) { + this.parent = this.resolveParent() + this.provides = this.parent ? this.parent.provides : Object.create(null) this.scope = effectScope(true) // props响应式数据代理 this.props = {} @@ -193,6 +195,13 @@ export default class MpxProxy { } } + resolveParent () { + if (isFunction(this.target.selectOwnerComponent)) { + const parent = this.target.selectOwnerComponent() + return parent ? parent.__mpxProxy : null + } + } + createRenderTask (isEmptyRender) { if ((!this.isMounted() && this.currentRenderTask) || (this.isMounted() && isEmptyRender)) { return @@ -232,16 +241,6 @@ export default class MpxProxy { // 页面/组件销毁清除上下文的缓存 contextMap.remove(this.uid) } - if (!isWeb && this.options.__type__ === 'page') { - // 小程序页面销毁时移除对应的 provide - if (isFunction(this.target.getPageId)) { - const pageId = this.target.getPageId() - const providesMap = global.__mpxProvidesMap - if (providesMap.__pages[pageId]) { - delete providesMap.__pages[pageId] - } - } - } this.callHook(BEFOREUNMOUNT) this.scope?.stop() if (this.update) this.update.active = false diff --git a/packages/core/src/platform/export/inject.js b/packages/core/src/platform/export/inject.js index ea73092074..66a6ef1f78 100644 --- a/packages/core/src/platform/export/inject.js +++ b/packages/core/src/platform/export/inject.js @@ -1,14 +1,8 @@ import { callWithErrorHandling, isFunction, isObject, warn } from '@mpxjs/utils' import { currentInstance } from '../../core/proxy' -const providesMap = { - /** 全局 scope */ - __app: Object.create(null), - /** 页面 scope */ - __pages: Object.create(null) -} - -global.__mpxProvidesMap = providesMap +/** 全局 scope */ +let appProvides = Object.create(null) /** @internal createApp() 初始化应用层 scope provide */ export function initAppProvides (appOptions) { @@ -18,22 +12,20 @@ export function initAppProvides (appOptions) { ? callWithErrorHandling(provideOpt.bind(appOptions), appOptions, 'createApp provide function') : provideOpt if (isObject(provided)) { - providesMap.__app = provided + appProvides = provided } else { warn('App provides must be an object or a function that returns an object.') } } } -function resolvePageId (context) { - if (context && isFunction(context.getPageId)) { - return context.getPageId() +function resolveProvides (vm) { + const provides = vm.provides + const parentProvides = vm.parent && vm.parent.provides + if (parentProvides === provides) { + return (vm.provides = Object.create(parentProvides)) } -} - -function resolvePageProvides (context) { - const pageId = resolvePageId(context) - return providesMap.__pages[pageId] || (providesMap.__pages[pageId] = Object.create(null)) + return provides } export function provide (key, value) { @@ -42,8 +34,7 @@ export function provide (key, value) { warn('provide() can only be used inside setup().') return } - // 小程序无法实现组件父级引用,所以 provide scope 设置为组件所在页面 - const provides = resolvePageProvides(instance.target) + const provides = resolveProvides(instance) provides[key] = value } @@ -53,11 +44,11 @@ export function inject (key, defaultValue, treatDefaultAsFactory = false) { warn('inject() can only be used inside setup()') return } - const provides = resolvePageProvides(instance.target) + const provides = resolveProvides(instance) if (key in provides) { return provides[key] - } else if (key in providesMap.__app) { - return providesMap.__app[key] + } else if (key in appProvides) { + return appProvides[key] } else if (arguments.length > 1) { return treatDefaultAsFactory && isFunction(defaultValue) ? defaultValue.call(instance && instance.target) From e4f8219cf5fb682e7b01a2c5a860a91dd538385e Mon Sep 17 00:00:00 2001 From: wangshunnn Date: Wed, 25 Dec 2024 16:15:43 +0800 Subject: [PATCH 02/10] feat: execute in created --- packages/core/src/core/proxy.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/src/core/proxy.js b/packages/core/src/core/proxy.js index b4c56db78d..6f22ef788c 100644 --- a/packages/core/src/core/proxy.js +++ b/packages/core/src/core/proxy.js @@ -118,8 +118,6 @@ export default class MpxProxy { // 收集setup中动态注册的hooks,小程序与web环境都需要 this.hooks = {} if (!isWeb) { - this.parent = this.resolveParent() - this.provides = this.parent ? this.parent.provides : Object.create(null) this.scope = effectScope(true) // props响应式数据代理 this.props = {} @@ -171,6 +169,8 @@ export default class MpxProxy { // web中BEFORECREATE钩子通过vue的beforeCreate钩子单独驱动 this.callHook(BEFORECREATE) setCurrentInstance(this) + this.parent = this.resolveParent() + this.provides = this.parent ? this.parent.provides : Object.create(null) // 在 props/data 初始化之前初始化 inject this.initInject() this.initProps() From e10ea210566a2d809e8234d91de2ab4ed45eb438 Mon Sep 17 00:00:00 2001 From: wangshunnn Date: Wed, 25 Dec 2024 16:51:45 +0800 Subject: [PATCH 03/10] feat: update docs --- docs-vuepress/guide/advance/provide-inject.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs-vuepress/guide/advance/provide-inject.md b/docs-vuepress/guide/advance/provide-inject.md index 15af05b8d3..f1c972910b 100644 --- a/docs-vuepress/guide/advance/provide-inject.md +++ b/docs-vuepress/guide/advance/provide-inject.md @@ -245,4 +245,4 @@ const foo = inject(key, 1) // ❌ 默认值是非字符串则会 TS 类型报错 ## 跨端差异 - Mpx 输出 Web 端后,使用规则与 Vue 一致,`provide/inject` 的生效范围严格遵行父子组件关系,只有父组件可以成功向子孙组件提供依赖。 -- Mpx 输出小程序端会略有不同,由于小程序原生框架限制,暂时无法在子组件获取真实渲染时的父组件引用关系,所以不能像 Vue 那样基于父组件原型继承来实现 `provide`。在 Mpx 底层实现中,我们将组件层的 `provide` 挂载在所属页面实例上,相当于将组件 scope 提升到页面 scope,可以理解成一种“降级模拟”。当然,这并不影响父组件向子孙组件 `provide` 的能力,只是会额外存在“**副作用**”:同一页面中的组件可以向页面中其他所有在其之后渲染子组件提供依赖。比如同一页面下的组件 A 可以向后渲染的兄弟组件 B 的子孙组件提供数据,这在 Web 端是不允许的。因此,针对小程序端可能出现的“副作用”需要开发者自行保证,可以结合上述注入名的管理优化来规避。 +- Mpx 输出小程序端后同样遵循类似 Web 端的父子组件关系,但是在 `slot` 场景下小程序表现会略有差异。举个例子:在组件 A 的模板中包含一个子组件 B,然后组件 B 通过 `slot` 包含子组件 C。该场景下:在 Web 端,组件 A 是 B 的父组件,B 是 C 的父组件,所以 A 和 B 都可以向 C 提供依赖。但在小程序端,B 和 C 的父组件都是 A,组件 B 不能再向 C 提供依赖。这个跨端差异或者说 **“副作用”** 可以理解成:小程序的父子组件关系是基于“组件树”,也就是组件模板维度,而 Web 端是基于“节点树”,也就是虚拟组件节点纬度。 From 9b2dbbc3248a5763487d1f1764ba2819407ebd57 Mon Sep 17 00:00:00 2001 From: wangshunnn Date: Wed, 25 Dec 2024 19:17:35 +0800 Subject: [PATCH 04/10] feat: update docs --- docs-vuepress/guide/advance/provide-inject.md | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/docs-vuepress/guide/advance/provide-inject.md b/docs-vuepress/guide/advance/provide-inject.md index f1c972910b..9c41c93535 100644 --- a/docs-vuepress/guide/advance/provide-inject.md +++ b/docs-vuepress/guide/advance/provide-inject.md @@ -245,4 +245,22 @@ const foo = inject(key, 1) // ❌ 默认值是非字符串则会 TS 类型报错 ## 跨端差异 - Mpx 输出 Web 端后,使用规则与 Vue 一致,`provide/inject` 的生效范围严格遵行父子组件关系,只有父组件可以成功向子孙组件提供依赖。 -- Mpx 输出小程序端后同样遵循类似 Web 端的父子组件关系,但是在 `slot` 场景下小程序表现会略有差异。举个例子:在组件 A 的模板中包含一个子组件 B,然后组件 B 通过 `slot` 包含子组件 C。该场景下:在 Web 端,组件 A 是 B 的父组件,B 是 C 的父组件,所以 A 和 B 都可以向 C 提供依赖。但在小程序端,B 和 C 的父组件都是 A,组件 B 不能再向 C 提供依赖。这个跨端差异或者说 **“副作用”** 可以理解成:小程序的父子组件关系是基于“组件树”,也就是组件模板维度,而 Web 端是基于“节点树”,也就是虚拟组件节点纬度。 +- Mpx 输出小程序端后同样遵循类似 Web 端的父子组件关系,但是在 `slot` 场景下小程序表现会略有差异。举个例子,如下代码所示:在组件 A 的 `template` 模板中包含子组件 B,然后组件 B 通过 `slot` 包含子组件 C,组件 B 和 C 都定义在组件 A 的模板中。该场景下:在 Web 端,组件 A 是 B 的父组件,B 是 C 的父组件,所以 A 和 B 都可以向 C 提供依赖。但在小程序端,B 和 C 的父组件都是 A,组件 B 不能再向 C 提供依赖。这个跨端差异或者说“副作用”可以理解成:Web 端是基于“节点树”,即虚拟组件节点纬度,而小程序的父子组件关系是基于“组件树”,即组件模板维度,也就是说当前组件的创建者(在 WXML/AXML 模板中定义了此组件的组件)才是它的父组件。 + +```html + + + + + +``` From c042a1edc459bc1610eb0edc4381bfa5e78f8d3f Mon Sep 17 00:00:00 2001 From: wangshunnn Date: Wed, 8 Jan 2025 19:05:30 +0800 Subject: [PATCH 05/10] feat: review --- packages/core/src/platform/export/inject.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/src/platform/export/inject.js b/packages/core/src/platform/export/inject.js index 66a6ef1f78..4e2e704361 100644 --- a/packages/core/src/platform/export/inject.js +++ b/packages/core/src/platform/export/inject.js @@ -44,8 +44,8 @@ export function inject (key, defaultValue, treatDefaultAsFactory = false) { warn('inject() can only be used inside setup()') return } - const provides = resolveProvides(instance) - if (key in provides) { + const provides = instance.parent && instance.parent.provides + if (provides && key in provides) { return provides[key] } else if (key in appProvides) { return appProvides[key] From 2aa58639fdf03a223d39f48e90a5b77c9defe308 Mon Sep 17 00:00:00 2001 From: wangshunnn Date: Tue, 14 Jan 2025 17:50:34 +0800 Subject: [PATCH 06/10] feat: support RN --- packages/core/src/core/proxy.js | 8 ++++++-- packages/core/src/platform/createApp.ios.js | 2 ++ packages/core/src/platform/export/inject.js | 19 ++++++++++++++++--- .../platform/patch/getDefaultOptions.ios.js | 18 ++++++++++++++++-- 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/packages/core/src/core/proxy.js b/packages/core/src/core/proxy.js index 6f22ef788c..b29cd68f50 100644 --- a/packages/core/src/core/proxy.js +++ b/packages/core/src/core/proxy.js @@ -169,8 +169,12 @@ export default class MpxProxy { // web中BEFORECREATE钩子通过vue的beforeCreate钩子单独驱动 this.callHook(BEFORECREATE) setCurrentInstance(this) - this.parent = this.resolveParent() - this.provides = this.parent ? this.parent.provides : Object.create(null) + if (isReact) { + this.parentProvides = this.options.parentProvides + } else { + this.parent = this.resolveParent() + this.provides = this.parent ? this.parent.provides : Object.create(null) + } // 在 props/data 初始化之前初始化 inject this.initInject() this.initProps() diff --git a/packages/core/src/platform/createApp.ios.js b/packages/core/src/platform/createApp.ios.js index e80861c4f5..e13796c5de 100644 --- a/packages/core/src/platform/createApp.ios.js +++ b/packages/core/src/platform/createApp.ios.js @@ -7,6 +7,7 @@ import Mpx from '../index' import { createElement, memo, useRef, useEffect } from 'react' import * as ReactNative from 'react-native' import { Image } from 'react-native' +import { initAppProvides } from './export/inject' const appHooksMap = makeMap(mergeLifecycle(LIFECYCLE).app) @@ -35,6 +36,7 @@ export default function createApp (options) { const { NavigationContainer, createStackNavigator, SafeAreaProvider } = global.__navigationHelper // app选项目前不需要进行转换 const { rawOptions, currentInject } = transferOptions(options, 'app', false) + initAppProvides(rawOptions.provide, rawOptions) const defaultOptions = filterOptions(spreadProp(rawOptions, 'methods'), appData) // 在页面script执行前填充getApp() global.getApp = function () { diff --git a/packages/core/src/platform/export/inject.js b/packages/core/src/platform/export/inject.js index 1f260a8850..13c847d00f 100644 --- a/packages/core/src/platform/export/inject.js +++ b/packages/core/src/platform/export/inject.js @@ -1,4 +1,4 @@ -import { callWithErrorHandling, isFunction, isObject, warn } from '@mpxjs/utils' +import { callWithErrorHandling, isFunction, isObject, isReact, warn } from '@mpxjs/utils' import { currentInstance } from '../../core/proxy' /** 全局 scope */ @@ -18,6 +18,15 @@ export function initAppProvides (provideOpt, instance) { } } +function resolveProvidesRN (vm) { + const provides = vm.provides + if (!provides) { + const parentProvides = vm.parentProvides + return (vm.provides = Object.create(parentProvides)) + } + return provides +} + function resolveProvides (vm) { const provides = vm.provides const parentProvides = vm.parent && vm.parent.provides @@ -33,7 +42,9 @@ export function provide (key, value) { warn('provide() can only be used inside setup().') return } - const provides = resolveProvides(instance) + const provides = isReact + ? resolveProvidesRN(instance) + : resolveProvides(instance) provides[key] = value } @@ -43,7 +54,9 @@ export function inject (key, defaultValue, treatDefaultAsFactory = false) { warn('inject() can only be used inside setup()') return } - const provides = instance.parent && instance.parent.provides + const provides = isReact + ? instance.parentProvides + : instance.parent && instance.parent.provides if (provides && key in provides) { return provides[key] } else if (key in appProvides) { diff --git a/packages/core/src/platform/patch/getDefaultOptions.ios.js b/packages/core/src/platform/patch/getDefaultOptions.ios.js index 0189823b53..22f47cd81f 100644 --- a/packages/core/src/platform/patch/getDefaultOptions.ios.js +++ b/packages/core/src/platform/patch/getDefaultOptions.ios.js @@ -1,4 +1,4 @@ -import { useEffect, useLayoutEffect, useSyncExternalStore, useRef, useMemo, useState, useCallback, createElement, memo, forwardRef, useImperativeHandle, useContext, Fragment, cloneElement } from 'react' +import { useEffect, useLayoutEffect, useSyncExternalStore, useRef, useMemo, useState, useCallback, createElement, memo, forwardRef, useImperativeHandle, useContext, Fragment, cloneElement, createContext } from 'react' import * as ReactNative from 'react-native' import { ReactiveEffect } from '../../observer/effect' import { watch } from '../../observer/watch' @@ -11,6 +11,8 @@ import { queueJob, hasPendingJob } from '../../observer/scheduler' import { createSelectorQuery, createIntersectionObserver } from '@mpxjs/api-proxy' import { IntersectionObserverContext, RouteContext, KeyboardAvoidContext } from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/context' +const ProviderContext = createContext(null) + function getSystemInfo () { const window = ReactNative.Dimensions.get('window') const screen = ReactNative.Dimensions.get('screen') @@ -384,10 +386,12 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) { const propsRef = useRef(null) const intersectionCtx = useContext(IntersectionObserverContext) const pageId = useContext(RouteContext) + const parentProvides = useContext(ProviderContext) propsRef.current = props let isFirst = false if (!instanceRef.current) { isFirst = true + rawOptions.parentProvides = parentProvides instanceRef.current = createInstance({ propsRef, type, rawOptions, currentInject, validProps, components, pageId, intersectionCtx }) } const instance = instanceRef.current @@ -472,8 +476,18 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) { const rootProps = getRootProps(props, validProps) rootProps.style = Object.assign({}, root.props.style, rootProps.style) // update root props - return cloneElement(root, rootProps) + return createElement( + ProviderContext.Provider, + { value: proxy.provides }, + cloneElement(root, rootProps) + ) } + + const provides = useMemo(() => proxy.provides, [proxy.provides]) + if (provides) { + return createElement(ProviderContext.Provider, { value: provides }, root) + } + return root })) From 6dbe66c357ca5e25928668b3ffe051b91c2fbee0 Mon Sep 17 00:00:00 2001 From: wangshunnn Date: Tue, 14 Jan 2025 19:19:20 +0800 Subject: [PATCH 07/10] docs: update RN --- docs-vuepress/guide/advance/provide-inject.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs-vuepress/guide/advance/provide-inject.md b/docs-vuepress/guide/advance/provide-inject.md index 9c41c93535..785a2fe44d 100644 --- a/docs-vuepress/guide/advance/provide-inject.md +++ b/docs-vuepress/guide/advance/provide-inject.md @@ -244,8 +244,9 @@ const foo = inject(key, 1) // ❌ 默认值是非字符串则会 TS 类型报错 ## 跨端差异 -- Mpx 输出 Web 端后,使用规则与 Vue 一致,`provide/inject` 的生效范围严格遵行父子组件关系,只有父组件可以成功向子孙组件提供依赖。 -- Mpx 输出小程序端后同样遵循类似 Web 端的父子组件关系,但是在 `slot` 场景下小程序表现会略有差异。举个例子,如下代码所示:在组件 A 的 `template` 模板中包含子组件 B,然后组件 B 通过 `slot` 包含子组件 C,组件 B 和 C 都定义在组件 A 的模板中。该场景下:在 Web 端,组件 A 是 B 的父组件,B 是 C 的父组件,所以 A 和 B 都可以向 C 提供依赖。但在小程序端,B 和 C 的父组件都是 A,组件 B 不能再向 C 提供依赖。这个跨端差异或者说“副作用”可以理解成:Web 端是基于“节点树”,即虚拟组件节点纬度,而小程序的父子组件关系是基于“组件树”,即组件模板维度,也就是说当前组件的创建者(在 WXML/AXML 模板中定义了此组件的组件)才是它的父组件。 +- Mpx 输出 **Web** 端,使用规则与 Vue 一致,`provide/inject` 的生效范围严格遵行父子组件关系,只有父组件可以成功向子孙组件提供依赖。 +- Mpx 输出 **RN** 端,框架内部基于 React 的 `useContext` 钩子来转换实现,表现和 Web 端一致。 +- Mpx 输出 **小程序** 端同样遵循类似 Vue 的父子组件关系,但是在 `slot` 场景下小程序表现会和 Web、RN 端略有差异。举个例子,如下代码所示:在组件 A 的 `template` 模板中包含子组件 B,然后组件 B 通过 `slot` 包含子组件 C,组件 B 和 C 都定义在组件 A 的模板中。该场景下:在 Web 端,组件 A 是 B 的父组件,B 是 C 的父组件,所以 A 和 B 都可以向 C 提供依赖。但在小程序端,B 和 C 的父组件都是 A,组件 B 不能再向 C 提供依赖。这个跨端差异或者说“副作用”可以理解成:Web 端是基于“节点树”,即虚拟组件节点纬度,而小程序的父子组件关系是基于“组件树”,即组件模板维度,也就是说当前组件的创建者(在 WXML/AXML 模板中定义了此组件的组件)才是它的父组件。 ```html From c3485e1c4666644852aea8eed50f2a62027bbd67 Mon Sep 17 00:00:00 2001 From: wangshunnn Date: Wed, 15 Jan 2025 11:04:50 +0800 Subject: [PATCH 08/10] feat: update --- packages/core/src/platform/export/inject.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/platform/export/inject.js b/packages/core/src/platform/export/inject.js index 13c847d00f..dca3c9f0e7 100644 --- a/packages/core/src/platform/export/inject.js +++ b/packages/core/src/platform/export/inject.js @@ -21,7 +21,7 @@ export function initAppProvides (provideOpt, instance) { function resolveProvidesRN (vm) { const provides = vm.provides if (!provides) { - const parentProvides = vm.parentProvides + const parentProvides = vm.parentProvides || null return (vm.provides = Object.create(parentProvides)) } return provides From 415920dea5f6ac1d52fec62d81d1487f935e1e72 Mon Sep 17 00:00:00 2001 From: wangshunnn Date: Tue, 21 Jan 2025 16:14:44 +0800 Subject: [PATCH 09/10] feat: update review --- packages/core/src/core/proxy.js | 4 +--- .../core/src/platform/patch/getDefaultOptions.ios.js | 9 +++++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/core/src/core/proxy.js b/packages/core/src/core/proxy.js index 4b6f0ae18e..998fe8089a 100644 --- a/packages/core/src/core/proxy.js +++ b/packages/core/src/core/proxy.js @@ -171,9 +171,7 @@ export default class MpxProxy { // web中BEFORECREATE钩子通过vue的beforeCreate钩子单独驱动 this.callHook(BEFORECREATE) setCurrentInstance(this) - if (isReact) { - this.parentProvides = this.options.parentProvides - } else { + if (!isReact) { this.parent = this.resolveParent() this.provides = this.parent ? this.parent.provides : Object.create(null) } diff --git a/packages/core/src/platform/patch/getDefaultOptions.ios.js b/packages/core/src/platform/patch/getDefaultOptions.ios.js index 25832380c2..b46dc0460b 100644 --- a/packages/core/src/platform/patch/getDefaultOptions.ios.js +++ b/packages/core/src/platform/patch/getDefaultOptions.ios.js @@ -195,7 +195,7 @@ const instanceProto = { } } -function createInstance ({ propsRef, type, rawOptions, currentInject, validProps, components, pageId, intersectionCtx, relation }) { +function createInstance ({ propsRef, type, rawOptions, currentInject, validProps, components, pageId, intersectionCtx, relation, parentProvides }) { const instance = Object.create(instanceProto, { dataset: { get () { @@ -282,6 +282,8 @@ function createInstance ({ propsRef, type, rawOptions, currentInject, validProps } const proxy = instance.__mpxProxy = new MpxProxy(rawOptions, instance) + // 在 created 之前设置 parentProvides + proxy.parentProvides = parentProvides proxy.created() Object.assign(proxy, { @@ -446,8 +448,7 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) { let isFirst = false if (!instanceRef.current) { isFirst = true - rawOptions.parentProvides = parentProvides - instanceRef.current = createInstance({ propsRef, type, rawOptions, currentInject, validProps, components, pageId, intersectionCtx, relation }) + instanceRef.current = createInstance({ propsRef, type, rawOptions, currentInject, validProps, components, pageId, intersectionCtx, relation, parentProvides }) } const instance = instanceRef.current useImperativeHandle(ref, () => { @@ -541,7 +542,7 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) { root = cloneElement(root, rootProps) } - const provides = useMemo(() => proxy.provides, [proxy.provides]) + const provides = proxy.provides if (provides) { root = createElement(ProviderContext.Provider, { value: provides }, root) } From 1ecdb14451d27f3ef0c2e545725e642a4623a978 Mon Sep 17 00:00:00 2001 From: wangshunnn Date: Wed, 22 Jan 2025 20:15:34 +0800 Subject: [PATCH 10/10] feat: update rn provides --- packages/core/src/core/proxy.js | 11 +++++++---- packages/core/src/platform/export/inject.js | 19 +++---------------- .../platform/patch/getDefaultOptions.ios.js | 8 ++++++-- 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/packages/core/src/core/proxy.js b/packages/core/src/core/proxy.js index 998fe8089a..88a2ec7155 100644 --- a/packages/core/src/core/proxy.js +++ b/packages/core/src/core/proxy.js @@ -171,10 +171,8 @@ export default class MpxProxy { // web中BEFORECREATE钩子通过vue的beforeCreate钩子单独驱动 this.callHook(BEFORECREATE) setCurrentInstance(this) - if (!isReact) { - this.parent = this.resolveParent() - this.provides = this.parent ? this.parent.provides : Object.create(null) - } + this.parent = this.resolveParent() + this.provides = this.parent ? this.parent.provides : Object.create(null) // 在 props/data 初始化之前初始化 inject this.initInject() this.initProps() @@ -200,6 +198,11 @@ export default class MpxProxy { } resolveParent () { + if (isReact) { + return { + provides: this.target.__getParentProvides + } + } if (isFunction(this.target.selectOwnerComponent)) { const parent = this.target.selectOwnerComponent() return parent ? parent.__mpxProxy : null diff --git a/packages/core/src/platform/export/inject.js b/packages/core/src/platform/export/inject.js index dca3c9f0e7..1f260a8850 100644 --- a/packages/core/src/platform/export/inject.js +++ b/packages/core/src/platform/export/inject.js @@ -1,4 +1,4 @@ -import { callWithErrorHandling, isFunction, isObject, isReact, warn } from '@mpxjs/utils' +import { callWithErrorHandling, isFunction, isObject, warn } from '@mpxjs/utils' import { currentInstance } from '../../core/proxy' /** 全局 scope */ @@ -18,15 +18,6 @@ export function initAppProvides (provideOpt, instance) { } } -function resolveProvidesRN (vm) { - const provides = vm.provides - if (!provides) { - const parentProvides = vm.parentProvides || null - return (vm.provides = Object.create(parentProvides)) - } - return provides -} - function resolveProvides (vm) { const provides = vm.provides const parentProvides = vm.parent && vm.parent.provides @@ -42,9 +33,7 @@ export function provide (key, value) { warn('provide() can only be used inside setup().') return } - const provides = isReact - ? resolveProvidesRN(instance) - : resolveProvides(instance) + const provides = resolveProvides(instance) provides[key] = value } @@ -54,9 +43,7 @@ export function inject (key, defaultValue, treatDefaultAsFactory = false) { warn('inject() can only be used inside setup()') return } - const provides = isReact - ? instance.parentProvides - : instance.parent && instance.parent.provides + const provides = instance.parent && instance.parent.provides if (provides && key in provides) { return provides[key] } else if (key in appProvides) { diff --git a/packages/core/src/platform/patch/getDefaultOptions.ios.js b/packages/core/src/platform/patch/getDefaultOptions.ios.js index b46dc0460b..4a86163184 100644 --- a/packages/core/src/platform/patch/getDefaultOptions.ios.js +++ b/packages/core/src/platform/patch/getDefaultOptions.ios.js @@ -246,6 +246,12 @@ function createInstance ({ propsRef, type, rawOptions, currentInject, validProps return currentInject.getRefsData || noop }, enumerable: false + }, + __getParentProvides: { + get () { + return parentProvides || null + }, + enumerable: false } }) @@ -282,8 +288,6 @@ function createInstance ({ propsRef, type, rawOptions, currentInject, validProps } const proxy = instance.__mpxProxy = new MpxProxy(rawOptions, instance) - // 在 created 之前设置 parentProvides - proxy.parentProvides = parentProvides proxy.created() Object.assign(proxy, {