@mpxjs/core 2.9.62 → 2.9.64

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,4 +8,4 @@ declare let __mpx_env__: string
8
8
  declare module '*?resolve' {
9
9
  const resourcePath: string
10
10
  export default resourcePath
11
- }
11
+ }
package/@types/index.d.ts CHANGED
@@ -7,10 +7,8 @@
7
7
  /// <reference path="./global.d.ts" />
8
8
  /// <reference path="./node.d.ts" />
9
9
 
10
- // @ts-ignore
11
10
  import { GetComputedType } from '@mpxjs/store'
12
11
 
13
- // @ts-ignore
14
12
  export * from '@mpxjs/store'
15
13
 
16
14
  // utils
@@ -34,7 +32,7 @@ type Data = object | (() => object)
34
32
  export type PropType<T> = {
35
33
  __type: T
36
34
  } & (
37
- T extends String
35
+ T extends string
38
36
  ? StringConstructor
39
37
  : T extends number
40
38
  ? NumberConstructor
@@ -427,9 +425,7 @@ export interface ComputedRef<T = any> extends WritableComputedRef<T> {
427
425
  [ComputedRefSymbol]: true
428
426
  }
429
427
 
430
- export interface WritableComputedRef<T> extends Ref<T> {
431
- // readonly effect: ReactiveEffect<T>
432
- }
428
+ export type WritableComputedRef<T> = Ref<T>
433
429
 
434
430
  type WatchCallback<T> = (
435
431
  value: T,
@@ -463,7 +459,6 @@ interface EffectScope {
463
459
  resume (ignoreDirty?: boolean): void
464
460
  }
465
461
 
466
-
467
462
  type StringObj = {
468
463
  [k: string]: string | StringObj
469
464
  }
@@ -490,7 +485,6 @@ interface UseI18n {
490
485
  mergeLocaleMessage (locale: string, messages: StringObj): void
491
486
  }
492
487
 
493
-
494
488
  export function ref<T extends object> (
495
489
  value: T
496
490
  ): [T] extends [Ref] ? T : Ref<UnwrapRef<T>>
@@ -530,7 +524,6 @@ export function computed<T> (
530
524
  options: WritableComputedOptions<T>
531
525
  ): WritableComputedRef<T>
532
526
 
533
-
534
527
  export function watchEffect (
535
528
  effect: (onCleanup: (cleanupFn: () => void) => void) => void,
536
529
  options?: WatchEffectOptions
@@ -546,7 +539,6 @@ export function watchPostEffect (
546
539
  options?: WatchEffectOptions
547
540
  ): void
548
541
 
549
-
550
542
  export function watch<T extends MultiWatchSources> (
551
543
  sources: [...T],
552
544
  callback: WatchCallback<{
package/@types/node.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- // @ts-ignore
2
1
  declare let global: Record<string, any> // in web, we use global varible to do some things, here to declare
3
2
 
4
3
  type Dict<T> = {
@@ -7,7 +6,6 @@ type Dict<T> = {
7
6
 
8
7
  type EnvType = Dict<string>
9
8
 
10
- // @ts-ignore
11
9
  declare let process: {
12
10
  env: EnvType
13
11
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mpxjs/core",
3
- "version": "2.9.62",
3
+ "version": "2.9.64",
4
4
  "description": "mpx runtime core",
5
5
  "keywords": [
6
6
  "miniprogram",
@@ -19,7 +19,7 @@
19
19
  ],
20
20
  "main": "src/index.js",
21
21
  "dependencies": {
22
- "@mpxjs/utils": "^2.9.59",
22
+ "@mpxjs/utils": "^2.9.64",
23
23
  "lodash": "^4.1.1",
24
24
  "miniprogram-api-typings": "^3.10.0"
25
25
  },
@@ -93,5 +93,5 @@
93
93
  "url": "https://github.com/didi/mpx/issues"
94
94
  },
95
95
  "sideEffects": false,
96
- "gitHead": "c31a343e7ef2c1c1585002752d8c50f016a858ae"
96
+ "gitHead": "803334dc0e600f219d514c27461aa7663b7a6653"
97
97
  }
@@ -5,7 +5,7 @@ import {
5
5
  import { implemented } from '../core/implement'
6
6
 
7
7
  // 暂不支持的wx选项,后期需要各种花式支持
8
- const unsupported = ['relations', 'moved', 'definitionFilter', 'onShareAppMessage', 'options']
8
+ const unsupported = ['relations', 'moved', 'definitionFilter', 'onShareAppMessage']
9
9
 
10
10
  function convertErrorDesc (key) {
11
11
  error(`Options.${key} is not supported in runtime conversion from wx to react native.`, global.currentResource)
package/src/index.js CHANGED
@@ -138,6 +138,7 @@ Mpx.config = {
138
138
  ignoreProxyWhiteList: ['id', 'dataset', 'data'],
139
139
  observeClassInstance: false,
140
140
  errorHandler: null,
141
+ warnHandler: null,
141
142
  proxyEventHandler: null,
142
143
  setDataHandler: null,
143
144
  forceFlushSync: false,
@@ -14,13 +14,13 @@ import { dynamicRefsMixin, dynamicRenderHelperMixin, dynamicSlotMixin } from '..
14
14
  import styleHelperMixin from './styleHelperMixin'
15
15
  import directiveHelperMixin from './directiveHelperMixin'
16
16
 
17
- export default function getBuiltInMixins (options, type) {
17
+ export default function getBuiltInMixins ({ type, rawOptions = {} }) {
18
18
  let bulitInMixins
19
19
  if (__mpx_mode__ === 'ios' || __mpx_mode__ === 'android') {
20
20
  bulitInMixins = [
21
21
  proxyEventMixin(),
22
22
  directiveHelperMixin(),
23
- styleHelperMixin(type),
23
+ styleHelperMixin(),
24
24
  refsMixin(),
25
25
  i18nMixin()
26
26
  ]
@@ -46,7 +46,7 @@ export default function getBuiltInMixins (options, type) {
46
46
  relationsMixin(type)
47
47
  ]
48
48
  // 此为纯增强类mixins,原生模式下不需要注入
49
- if (!options.__nativeRender__) {
49
+ if (!rawOptions.__nativeRender__) {
50
50
  bulitInMixins = bulitInMixins.concat([
51
51
  renderHelperMixin(),
52
52
  showMixin(type),
@@ -1,78 +1,55 @@
1
- import { BEFORECREATE, CREATED } from '../../core/innerLifecycle'
1
+ import { BEFORECREATE } from '../../core/innerLifecycle'
2
2
  import { createSelectorQuery } from '@mpxjs/api-proxy'
3
- import { computed } from '../../observer/computed'
4
3
 
5
4
  export default function getRefsMixin () {
6
5
  return {
7
6
  [BEFORECREATE] () {
8
7
  this.__refs = {}
9
8
  this.$refs = {}
10
- },
11
- // __getRefs强依赖数据响应,需要在CREATED中执行
12
- [CREATED] () {
13
9
  this.__getRefs()
14
10
  },
15
11
  methods: {
16
12
  __getRefs () {
17
13
  const refs = this.__getRefsData() || []
18
14
  const target = this
19
- this.__selectorMap = computed(() => {
20
- const selectorMap = {}
21
- refs.forEach(({ key, type, sKeys }) => {
22
- // sKeys 是使用 wx:ref 没有值的标记场景,支持运行时的 createSelectorQuery 的使用
23
- if (sKeys) {
24
- sKeys.forEach((item = {}) => {
25
- const computedKey = item.key
26
- const prefix = item.prefix
27
- const selectors = this[computedKey] || ''
28
- selectors.trim().split(/\s+/).forEach(item => {
29
- const selector = prefix + item
30
- selectorMap[selector] = selectorMap[selector] || []
31
- selectorMap[selector].push({ type, key })
32
- })
33
- })
34
- } else {
35
- selectorMap[key] = selectorMap[key] || []
36
- selectorMap[key].push({ type, key })
15
+ refs.forEach(({ key, type, all }) => {
16
+ Object.defineProperty(this.$refs, key, {
17
+ enumerable: true,
18
+ configurable: true,
19
+ get () {
20
+ if (type === 'component') {
21
+ return all ? target.selectAllComponents(key) : target.selectComponent(key)
22
+ } else {
23
+ return createSelectorQuery().in(target).select(key, all)
24
+ }
37
25
  }
38
26
  })
39
- return selectorMap
40
- })
41
- refs.forEach(({ key, type, all, sKeys }) => {
42
- // 如果没有 sKey 说明使用的是 wx:ref="xxx" 的场景
43
- if (!sKeys) {
44
- Object.defineProperty(this.$refs, key, {
45
- enumerable: true,
46
- configurable: true,
47
- get () {
48
- const refs = target.__refs[key] || []
49
- if (type === 'component') {
50
- return all ? refs : refs[0]
51
- } else {
52
- return createSelectorQuery().in(target).select(key, all)
53
- }
54
- }
55
- })
56
- }
57
27
  })
58
28
  },
59
- __getRefVal (key) {
29
+ __getRefVal (type, selectorsConf) {
60
30
  return (instance) => {
61
31
  if (instance) {
62
- this.__refs[key] = this.__refs[key] || []
63
- this.__refs[key].push(instance)
32
+ selectorsConf.forEach((item = []) => {
33
+ const [prefix, selectors = ''] = item
34
+ if (selectors) {
35
+ selectors.trim().split(/\s+/).forEach(selector => {
36
+ const refKey = prefix + selector
37
+ this.__refs[refKey] = this.__refs[refKey] || []
38
+ this.__refs[refKey].push({ type, instance })
39
+ })
40
+ }
41
+ })
64
42
  }
65
43
  }
66
44
  },
67
45
  __selectRef (selector, refType, all = false) {
68
46
  const splitedSelector = selector.match(/(#|\.)?[^.#]+/g) || []
69
47
  const refsArr = splitedSelector.map(selector => {
70
- const selectorMap = this.__selectorMap?.value[selector] || []
48
+ const refs = this.__refs[selector] || []
71
49
  const res = []
72
- selectorMap.forEach(({ type, key }) => {
50
+ refs.forEach(({ type, instance }) => {
73
51
  if (type === refType) {
74
- const _refs = this.__refs[key] || []
75
- res.push(..._refs)
52
+ res.push(instance)
76
53
  }
77
54
  })
78
55
  return res
@@ -1,5 +1,56 @@
1
- import { isObject, isArray, dash2hump, isFunction } from '@mpxjs/utils'
2
- import { Dimensions } from 'react-native'
1
+ import { isObject, isArray, dash2hump, isFunction, cached } from '@mpxjs/utils'
2
+ import { Dimensions, StyleSheet } from 'react-native'
3
+
4
+ function rpx (value) {
5
+ const { width } = Dimensions.get('screen')
6
+ // rn 单位 dp = 1(css)px = 1 物理像素 * pixelRatio(像素比)
7
+ // px = rpx * (750 / 屏幕宽度)
8
+ return value * width / 750
9
+ }
10
+ function vw (value) {
11
+ const { width } = Dimensions.get('screen')
12
+ return value * width / 100
13
+ }
14
+ function vh (value) {
15
+ const { height } = Dimensions.get('screen')
16
+ return value * height / 100
17
+ }
18
+
19
+ global.__unit = {
20
+ rpx,
21
+ vw,
22
+ vh
23
+ }
24
+ global.__hairlineWidth = StyleSheet.hairlineWidth
25
+
26
+ const escapeReg = /[()[\]{}#!.:,%'"+$]/g
27
+ const escapeMap = {
28
+ '(': '_pl_',
29
+ ')': '_pr_',
30
+ '[': '_bl_',
31
+ ']': '_br_',
32
+ '{': '_cl_',
33
+ '}': '_cr_',
34
+ '#': '_h_',
35
+ '!': '_i_',
36
+ '/': '_s_',
37
+ '.': '_d_',
38
+ ':': '_c_',
39
+ ',': '_2c_',
40
+ '%': '_p_',
41
+ '\'': '_q_',
42
+ '"': '_dq_',
43
+ '+': '_a_',
44
+ $: '_si_'
45
+ }
46
+
47
+ const mpEscape = cached((str) => {
48
+ return str.replace(escapeReg, function (match) {
49
+ if (escapeMap[match]) return escapeMap[match]
50
+ // unknown escaped
51
+ return '_u_'
52
+ })
53
+ })
3
54
 
4
55
  function concat (a = '', b = '') {
5
56
  return a ? b ? (a + ' ' + b) : a : b
@@ -41,10 +92,12 @@ function stringifyDynamicClass (value) {
41
92
 
42
93
  const listDelimiter = /;(?![^(]*[)])/g
43
94
  const propertyDelimiter = /:(.+)/
44
- const rpxRegExp = /^\s*(-?\d+(\.\d+)?)rpx\s*$/
45
- const pxRegExp = /^\s*(-?\d+(\.\d+)?)(px)?\s*$/
95
+ const unitRegExp = /^\s*(-?\d+(?:\.\d+)?)(rpx|vw|vh)\s*$/
96
+ const numberRegExp = /^\s*(-?\d+(\.\d+)?)(px)?\s*$/
97
+ const hairlineRegExp = /^\s*hairlineWidth\s*$/
98
+ const varRegExp = /^--/
46
99
 
47
- function parseStyleText (cssText = '') {
100
+ const parseStyleText = cached((cssText = '') => {
48
101
  const res = {}
49
102
  const arr = cssText.split(listDelimiter)
50
103
  for (let i = 0; i < arr.length; i++) {
@@ -52,13 +105,14 @@ function parseStyleText (cssText = '') {
52
105
  if (item) {
53
106
  const tmp = item.split(propertyDelimiter)
54
107
  if (tmp.length > 1) {
55
- const k = dash2hump(tmp[0].trim())
108
+ let k = tmp[0].trim()
109
+ k = varRegExp.test(k) ? k : dash2hump(k)
56
110
  res[k] = tmp[1].trim()
57
111
  }
58
112
  }
59
113
  }
60
114
  return res
61
- }
115
+ })
62
116
 
63
117
  function normalizeDynamicStyle (value) {
64
118
  if (!value) return {}
@@ -79,48 +133,44 @@ function mergeObjectArray (arr) {
79
133
  return res
80
134
  }
81
135
 
82
- function transformStyleObj (context, styleObj) {
136
+ function transformStyleObj (styleObj) {
83
137
  const keys = Object.keys(styleObj)
84
138
  const transformed = {}
85
139
  keys.forEach((prop) => {
86
- // todo 检测不支持的prop
87
140
  let value = styleObj[prop]
88
141
  let matched
89
- if ((matched = pxRegExp.exec(value))) {
142
+ if ((matched = numberRegExp.exec(value))) {
90
143
  value = +matched[1]
91
- } else if ((matched = rpxRegExp.exec(value))) {
92
- value = context.__rpx(+matched[1])
144
+ } else if ((matched = unitRegExp.exec(value))) {
145
+ value = global.__unit[matched[2]](+matched[1])
146
+ } else if (hairlineRegExp.test(value)) {
147
+ value = StyleSheet.hairlineWidth
93
148
  }
94
- // todo 检测不支持的value
95
149
  transformed[prop] = value
96
150
  })
97
151
  return transformed
98
152
  }
99
153
 
100
- export default function styleHelperMixin (type) {
154
+ export default function styleHelperMixin () {
101
155
  return {
102
156
  methods: {
103
- __rpx (value) {
104
- const { width } = Dimensions.get('screen')
105
- // rn 单位 dp = 1(css)px = 1 物理像素 * pixelRatio(像素比)
106
- // px = rpx * (750 / 屏幕宽度)
107
- return value * width / 750
108
- },
109
157
  __getClass (staticClass, dynamicClass) {
110
158
  return concat(staticClass, stringifyDynamicClass(dynamicClass))
111
159
  },
112
- __getStyle (staticClass, dynamicClass, staticStyle, dynamicStyle, show) {
113
- // todo 每次返回新对象会导致react memo优化失效,需要考虑优化手段
160
+ __getStyle (staticClass, dynamicClass, staticStyle, dynamicStyle, hide) {
114
161
  const result = {}
115
162
  const classMap = {}
116
- if (type === 'page' && isFunction(global.__getAppClassMap)) {
117
- Object.assign(classMap, global.__getAppClassMap.call(this))
163
+ // todo 全局样式在每个页面和组件中生效,以支持全局原子类,后续支持样式模块复用后可考虑移除
164
+ if (isFunction(global.__getAppClassMap)) {
165
+ Object.assign(classMap, global.__getAppClassMap())
118
166
  }
119
167
  if (isFunction(this.__getClassMap)) {
120
168
  Object.assign(classMap, this.__getClassMap())
121
169
  }
170
+
122
171
  if (staticClass || dynamicClass) {
123
- const classString = concat(staticClass, stringifyDynamicClass(dynamicClass))
172
+ // todo 当前为了复用小程序unocss产物,暂时进行mpEscape,等后续正式支持unocss后可不进行mpEscape
173
+ const classString = mpEscape(concat(staticClass, stringifyDynamicClass(dynamicClass)))
124
174
  classString.split(/\s+/).forEach((className) => {
125
175
  if (classMap[className]) {
126
176
  Object.assign(result, classMap[className])
@@ -132,11 +182,11 @@ export default function styleHelperMixin (type) {
132
182
  }
133
183
 
134
184
  if (staticStyle || dynamicStyle) {
135
- const styleObj = Object.assign(parseStyleText(staticStyle), normalizeDynamicStyle(dynamicStyle))
136
- Object.assign(result, transformStyleObj(this, styleObj))
185
+ const styleObj = Object.assign({}, parseStyleText(staticStyle), normalizeDynamicStyle(dynamicStyle))
186
+ Object.assign(result, transformStyleObj(styleObj))
137
187
  }
138
188
 
139
- if (show === false) {
189
+ if (hide) {
140
190
  Object.assign(result, {
141
191
  display: 'none'
142
192
  })
@@ -58,7 +58,7 @@ export default function createFactory (type) {
58
58
  // 不接受mixin中的setup配置
59
59
  // 注入内建的mixins, 内建mixin是按原始平台编写的,所以合并规则和rootMixins保持一致
60
60
  // 将合并后的用户定义的rawOptions传入获取当前应该注入的内建mixins
61
- rawOptions.mixins = getBuiltInMixins(rawOptions, type)
61
+ rawOptions.mixins = getBuiltInMixins({ type, rawOptions, currentInject })
62
62
  const defaultOptions = getDefaultOptions({ type, rawOptions, currentInject })
63
63
  if (__mpx_mode__ === 'web' || __mpx_mode__ === 'ios' || __mpx_mode__ === 'android') {
64
64
  global.__mpxOptionsMap = global.__mpxOptionsMap || {}
@@ -1,9 +1,9 @@
1
- import { useEffect, useLayoutEffect, useSyncExternalStore, useRef, useMemo, createElement, memo, forwardRef, useImperativeHandle, useContext, createContext, Fragment } from 'react'
1
+ import { useEffect, useLayoutEffect, useSyncExternalStore, useRef, useMemo, createElement, memo, forwardRef, useImperativeHandle, useContext, createContext, Fragment, cloneElement } from 'react'
2
2
  import * as ReactNative from 'react-native'
3
3
  import { ReactiveEffect } from '../../../observer/effect'
4
4
  import { watch } from '../../../observer/watch'
5
5
  import { reactive, set, del } from '../../../observer/reactive'
6
- import { hasOwn, isFunction, noop, isObject, error, getByPath, collectDataset } from '@mpxjs/utils'
6
+ import { hasOwn, isFunction, noop, isObject, error, getByPath, collectDataset, hump2dash } from '@mpxjs/utils'
7
7
  import MpxProxy from '../../../core/proxy'
8
8
  import { BEFOREUPDATE, ONLOAD, UPDATED, ONSHOW, ONHIDE, ONRESIZE, REACTHOOKSEXEC } from '../../../core/innerLifecycle'
9
9
  import mergeOptions from '../../../core/mergeOptions'
@@ -46,15 +46,31 @@ function createEffect (proxy, components) {
46
46
  proxy.effect = new ReactiveEffect(() => {
47
47
  // reset instance
48
48
  proxy.target.__resetInstance()
49
- return proxy.target.__injectedRender(createElement, getComponent, proxy.target.__getRootProps())
49
+ return proxy.target.__injectedRender(createElement, getComponent)
50
50
  }, () => queueJob(update), proxy.scope)
51
51
  }
52
52
 
53
- function createInstance ({ propsRef, type, rawOptions, currentInject, validProps, components }) {
53
+ function getRootProps (props) {
54
+ const rootProps = {}
55
+ for (const key in props) {
56
+ if (hasOwn(props, key)) {
57
+ const match = /^(bind|catch|capture-bind|capture-catch|style|enable-var):?(.*?)(?:\.(.*))?$/.exec(key)
58
+ if (match) {
59
+ rootProps[key] = props[key]
60
+ }
61
+ }
62
+ }
63
+ return rootProps
64
+ }
65
+
66
+ function createInstance ({ propsRef, type, rawOptions, currentInject, validProps, components, pageId }) {
54
67
  const instance = Object.create({
55
68
  setData (data, callback) {
56
69
  return this.__mpxProxy.forceUpdate(data, { sync: true }, callback)
57
70
  },
71
+ getPageId () {
72
+ return pageId
73
+ },
58
74
  __getProps () {
59
75
  const props = propsRef.current
60
76
  const propsData = {}
@@ -62,31 +78,23 @@ function createInstance ({ propsRef, type, rawOptions, currentInject, validProps
62
78
  if (hasOwn(props, key)) {
63
79
  propsData[key] = props[key]
64
80
  } else {
65
- let field = validProps[key]
66
- if (isFunction(field) || field === null) {
67
- field = {
68
- type: field
81
+ const altKey = hump2dash(key)
82
+ if (hasOwn(props, altKey)) {
83
+ propsData[key] = props[altKey]
84
+ } else {
85
+ let field = validProps[key]
86
+ if (isFunction(field) || field === null) {
87
+ field = {
88
+ type: field
89
+ }
69
90
  }
91
+ // 处理props默认值
92
+ propsData[key] = field.value
70
93
  }
71
- // 处理props默认值
72
- propsData[key] = field.value
73
94
  }
74
95
  })
75
96
  return propsData
76
97
  },
77
- __getRootProps () {
78
- const props = propsRef.current
79
- const rootProps = {}
80
- for (const key in props) {
81
- if (hasOwn(props, key)) {
82
- const match = /^(bind|catch|capture-bind|capture-catch|style):?(.*?)(?:\.(.*))?$/.exec(key)
83
- if (match) {
84
- rootProps[key] = props[key]
85
- }
86
- }
87
- }
88
- return rootProps
89
- },
90
98
  __resetInstance () {
91
99
  this.__refs = {}
92
100
  this.__dispatchedSlotSet = new WeakSet()
@@ -97,22 +105,19 @@ function createInstance ({ propsRef, type, rawOptions, currentInject, validProps
97
105
  const result = []
98
106
  if (Array.isArray(children)) {
99
107
  children.forEach(child => {
100
- if (child && child.props && child.props.slot === name) {
108
+ if (child?.props?.slot === name) {
101
109
  result.push(child)
102
110
  }
103
111
  })
104
112
  } else {
105
- if (children && children.props && children.props.slot === name) {
113
+ if (children?.props?.slot === name) {
106
114
  result.push(children)
107
115
  }
108
116
  }
109
117
  return result.filter(item => {
110
- if (this.__dispatchedSlotSet.has(item)) {
111
- return false
112
- } else {
113
- this.__dispatchedSlotSet.add(item)
114
- return true
115
- }
118
+ if (!isObject(item) || this.__dispatchedSlotSet.has(item)) return false
119
+ this.__dispatchedSlotSet.add(item)
120
+ return true
116
121
  })
117
122
  }
118
123
  return null
@@ -255,7 +260,7 @@ function hasPageHook (mpxProxy, hookNames) {
255
260
  })
256
261
  }
257
262
 
258
- const routeContext = createContext(null)
263
+ const RouteContext = createContext(null)
259
264
 
260
265
  const triggerPageStatusHook = (mpxProxy, event) => {
261
266
  mpxProxy.callHook(event === 'show' ? ONSHOW : ONHIDE)
@@ -279,13 +284,7 @@ const triggerResizeEvent = (mpxProxy) => {
279
284
  }
280
285
  }
281
286
 
282
- function usePageContext (mpxProxy, instance) {
283
- const { pageId } = useContext(routeContext) || {}
284
-
285
- instance.getPageId = () => {
286
- return pageId
287
- }
288
-
287
+ function usePageEffect (mpxProxy, pageId) {
289
288
  useEffect(() => {
290
289
  let unWatch
291
290
  const hasShowHook = hasPageHook(mpxProxy, [ONSHOW, 'show'])
@@ -302,7 +301,6 @@ function usePageContext (mpxProxy, instance) {
302
301
  })
303
302
  }
304
303
  }
305
-
306
304
  return () => {
307
305
  unWatch && unWatch()
308
306
  }
@@ -346,11 +344,12 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
346
344
  const defaultOptions = memo(forwardRef((props, ref) => {
347
345
  const instanceRef = useRef(null)
348
346
  const propsRef = useRef(null)
347
+ const pageId = useContext(RouteContext)
349
348
  propsRef.current = props
350
349
  let isFirst = false
351
350
  if (!instanceRef.current) {
352
351
  isFirst = true
353
- instanceRef.current = createInstance({ propsRef, type, rawOptions, currentInject, validProps, components })
352
+ instanceRef.current = createInstance({ propsRef, type, rawOptions, currentInject, validProps, components, pageId })
354
353
  }
355
354
  const instance = instanceRef.current
356
355
  useImperativeHandle(ref, () => {
@@ -364,9 +363,14 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
364
363
  useEffect(() => {
365
364
  if (!isFirst) {
366
365
  // 处理props更新
367
- Object.keys(props).forEach(key => {
368
- if (hasOwn(validProps, key)) {
366
+ Object.keys(validProps).forEach((key) => {
367
+ if (hasOwn(props, key)) {
369
368
  instance[key] = props[key]
369
+ } else {
370
+ const altKey = hump2dash(key)
371
+ if (hasOwn(props, altKey)) {
372
+ instance[key] = props[altKey]
373
+ }
370
374
  }
371
375
  })
372
376
  }
@@ -376,7 +380,7 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
376
380
  }
377
381
  })
378
382
 
379
- usePageContext(proxy, instance)
383
+ usePageEffect(proxy, pageId)
380
384
 
381
385
  useEffect(() => {
382
386
  if (type === 'page') {
@@ -385,6 +389,7 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
385
389
  proxy.mounted()
386
390
  return () => {
387
391
  proxy.unmounted()
392
+ proxy.target.__resetInstance()
388
393
  if (type === 'page') {
389
394
  delete global.__mpxPagesMap[props.route.key]
390
395
  }
@@ -393,7 +398,14 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
393
398
 
394
399
  useSyncExternalStore(proxy.subscribe, proxy.getSnapshot)
395
400
 
396
- return rawOptions.__disableMemo ? proxy.effect.run() : useMemo(() => proxy.effect.run(), [proxy.stateVersion])
401
+ const root = rawOptions.options?.disableMemo ? proxy.effect.run() : useMemo(() => proxy.effect.run(), [proxy.stateVersion])
402
+ if (root) {
403
+ const rootProps = getRootProps(props)
404
+ rootProps.style = { ...root.props.style, ...rootProps.style }
405
+ // update root props
406
+ return cloneElement(root, rootProps)
407
+ }
408
+ return root
397
409
  }))
398
410
 
399
411
  if (type === 'page') {
@@ -416,27 +428,28 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
416
428
 
417
429
  navigation.insets = useSafeAreaInsets()
418
430
 
419
- return createElement(Provider,
420
- null,
421
- createElement(GestureHandlerRootView,
422
- {
423
- style: {
424
- flex: 1,
425
- backgroundColor: pageConfig.backgroundColor || '#ffffff'
426
- },
427
- onLayout (e) {
428
- navigation.layout = e.nativeEvent.layout
429
- }
431
+ return createElement(GestureHandlerRootView,
432
+ {
433
+ style: {
434
+ flex: 1,
435
+ backgroundColor: pageConfig.backgroundColor || '#ffffff'
430
436
  },
431
- createElement(routeContext.Provider,
437
+ onLayout (e) {
438
+ navigation.layout = e.nativeEvent.layout
439
+ }
440
+ },
441
+ // todo custom portal host for active route
442
+ createElement(Provider,
443
+ null,
444
+ createElement(RouteContext.Provider,
432
445
  {
433
- value: { pageId: currentPageId }
446
+ value: currentPageId
434
447
  },
435
448
  createElement(defaultOptions,
436
449
  {
437
450
  navigation,
438
451
  route,
439
- pageConfig
452
+ id: currentPageId
440
453
  }
441
454
  )
442
455
  )