@mpxjs/core 2.9.65 → 2.9.66

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mpxjs/core",
3
- "version": "2.9.65",
3
+ "version": "2.9.66",
4
4
  "description": "mpx runtime core",
5
5
  "keywords": [
6
6
  "miniprogram",
@@ -97,5 +97,5 @@
97
97
  "url": "https://github.com/didi/mpx/issues"
98
98
  },
99
99
  "sideEffects": false,
100
- "gitHead": "24efa90e90b4d42c285ca61739cb9e4d0696976c"
100
+ "gitHead": "ff9eb06a3be28538870823cebf813ed56f39bbd7"
101
101
  }
package/src/core/proxy.js CHANGED
@@ -106,6 +106,7 @@ export default class MpxProxy {
106
106
  this.uid = uid++
107
107
  this.name = options.name || ''
108
108
  this.options = options
109
+ this.ignoreReactivePattern = this.options.options?.ignoreReactivePattern
109
110
  // beforeCreate -> created -> mounted -> unmounted
110
111
  this.state = BEFORECREATE
111
112
  this.ignoreProxyMap = makeMap(Mpx.config.ignoreProxyWhiteList)
@@ -135,6 +136,21 @@ export default class MpxProxy {
135
136
  this.initApi()
136
137
  }
137
138
 
139
+ processIgnoreReactive (obj) {
140
+ if (this.ignoreReactivePattern && isObject(obj)) {
141
+ Object.keys(obj).forEach((key) => {
142
+ if (this.ignoreReactivePattern.test(key)) {
143
+ Object.defineProperty(obj, key, {
144
+ enumerable: true,
145
+ // set configurable to false to skip defineReactive
146
+ configurable: false
147
+ })
148
+ }
149
+ })
150
+ }
151
+ return obj
152
+ }
153
+
138
154
  created () {
139
155
  if (__mpx_dynamic_runtime__) {
140
156
  // 缓存上下文,在 destoryed 阶段删除
@@ -208,6 +224,11 @@ export default class MpxProxy {
208
224
  if (this.update) this.update.active = false
209
225
  this.callHook(UNMOUNTED)
210
226
  this.state = UNMOUNTED
227
+ if (this._intersectionObservers) {
228
+ this._intersectionObservers.forEach((observer) => {
229
+ observer.disconnect()
230
+ })
231
+ }
211
232
  }
212
233
 
213
234
  isUnmounted () {
@@ -249,7 +270,7 @@ export default class MpxProxy {
249
270
  } else {
250
271
  this.props = diffAndCloneA(this.target.__getProps(this.options)).clone
251
272
  }
252
- reactive(this.props)
273
+ reactive(this.processIgnoreReactive(this.props))
253
274
  proxy(this.target, this.props, undefined, false, this.createProxyConflictHandler('props'))
254
275
  }
255
276
 
@@ -287,7 +308,7 @@ export default class MpxProxy {
287
308
  if (isFunction(dataFn)) {
288
309
  Object.assign(this.data, callWithErrorHandling(dataFn.bind(this.target), this, 'data function'))
289
310
  }
290
- reactive(this.data)
311
+ reactive(this.processIgnoreReactive(this.data))
291
312
  proxy(this.target, this.data, undefined, false, this.createProxyConflictHandler('data'))
292
313
  this.collectLocalKeys(this.data)
293
314
  }
@@ -419,7 +440,7 @@ export default class MpxProxy {
419
440
  if (hasOwn(renderData, key)) {
420
441
  const data = renderData[key]
421
442
  const firstKey = getFirstKey(key)
422
- if (!this.localKeysMap[firstKey]) {
443
+ if (!this.localKeysMap[firstKey] || (this.ignoreReactivePattern && this.ignoreReactivePattern.test(firstKey))) {
423
444
  continue
424
445
  }
425
446
  // 外部clone,用于只需要clone的场景
@@ -1,4 +1,4 @@
1
- import { isObject, isArray, dash2hump, isFunction, cached } from '@mpxjs/utils'
1
+ import { isObject, isArray, dash2hump, isFunction, cached, getFocusedNavigation } from '@mpxjs/utils'
2
2
  import { Dimensions, StyleSheet } from 'react-native'
3
3
 
4
4
  function rpx (value) {
@@ -12,7 +12,8 @@ function vw (value) {
12
12
  return value * width / 100
13
13
  }
14
14
  function vh (value) {
15
- const { height } = Dimensions.get('screen')
15
+ const navigation = getFocusedNavigation()
16
+ const height = navigation?.layout?.height || Dimensions.get('screen').height
16
17
  return value * height / 100
17
18
  }
18
19
 
@@ -1,4 +1,3 @@
1
-
2
1
  export {
3
2
  watchEffect,
4
3
  watchSyncEffect,
@@ -7,6 +7,7 @@ if (__mpx_mode__ === 'web') {
7
7
  builtInKeys = [
8
8
  'proto',
9
9
  'mixins',
10
+ 'initData',
10
11
  'mpxCustomKeysForBlend',
11
12
  'mpxConvertMode',
12
13
  'mpxFileResource',
@@ -20,6 +21,7 @@ if (__mpx_mode__ === 'web') {
20
21
  'dataFn',
21
22
  'proto',
22
23
  'mixins',
24
+ 'initData',
23
25
  'watch',
24
26
  'computed',
25
27
  'mpxCustomKeysForBlend',
@@ -1,14 +1,15 @@
1
- import { useEffect, useLayoutEffect, useSyncExternalStore, useRef, useMemo, createElement, memo, forwardRef, useImperativeHandle, useContext, createContext, Fragment, cloneElement } from 'react'
1
+ import { useEffect, useLayoutEffect, useSyncExternalStore, useRef, useMemo, useCallback, 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, hump2dash } from '@mpxjs/utils'
6
+ import { hasOwn, isFunction, noop, isObject, 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'
10
10
  import { queueJob } from '../../../observer/scheduler'
11
- import { createSelectorQuery } from '@mpxjs/api-proxy'
11
+ import { createSelectorQuery, createIntersectionObserver } from '@mpxjs/api-proxy'
12
+ import { IntersectionObserverContext } from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/context'
12
13
 
13
14
  function getSystemInfo () {
14
15
  const window = ReactNative.Dimensions.get('window')
@@ -68,7 +69,7 @@ function getRootProps (props) {
68
69
  return rootProps
69
70
  }
70
71
 
71
- function createInstance ({ propsRef, type, rawOptions, currentInject, validProps, components, pageId }) {
72
+ function createInstance ({ propsRef, type, rawOptions, currentInject, validProps, components, pageId, intersectionCtx }) {
72
73
  const instance = Object.create({
73
74
  setData (data, callback) {
74
75
  return this.__mpxProxy.forceUpdate(data, { sync: true }, callback)
@@ -183,8 +184,8 @@ function createInstance ({ propsRef, type, rawOptions, currentInject, validProps
183
184
  createSelectorQuery () {
184
185
  return createSelectorQuery().in(this)
185
186
  },
186
- createIntersectionObserver () {
187
- error('createIntersectionObserver is not supported in react native, please use ref instead')
187
+ createIntersectionObserver (opt) {
188
+ return createIntersectionObserver(this, opt, intersectionCtx)
188
189
  },
189
190
  ...rawOptions.methods
190
191
  }, {
@@ -349,12 +350,13 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
349
350
  const defaultOptions = memo(forwardRef((props, ref) => {
350
351
  const instanceRef = useRef(null)
351
352
  const propsRef = useRef(null)
353
+ const intersectionCtx = useContext(IntersectionObserverContext)
352
354
  const pageId = useContext(RouteContext)
353
355
  propsRef.current = props
354
356
  let isFirst = false
355
357
  if (!instanceRef.current) {
356
358
  isFirst = true
357
- instanceRef.current = createInstance({ propsRef, type, rawOptions, currentInject, validProps, components, pageId })
359
+ instanceRef.current = createInstance({ propsRef, type, rawOptions, currentInject, validProps, components, pageId, intersectionCtx })
358
360
  }
359
361
  const instance = instanceRef.current
360
362
  useImperativeHandle(ref, () => {
@@ -413,18 +415,19 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
413
415
  return root
414
416
  }))
415
417
 
418
+ if (rawOptions.options?.isCustomText) {
419
+ defaultOptions.isCustomText = true
420
+ }
421
+
416
422
  if (type === 'page') {
417
423
  const { Provider, useSafeAreaInsets, GestureHandlerRootView } = global.__navigationHelper
418
424
  const pageConfig = Object.assign({}, global.__mpxPageConfig, currentInject.pageConfig)
419
425
  const Page = ({ navigation, route }) => {
420
- const rootRef = useRef(null)
421
426
  const currentPageId = useMemo(() => ++pageId, [])
427
+ const intersectionObservers = useRef({})
422
428
  usePageStatus(navigation, currentPageId)
423
429
 
424
430
  useLayoutEffect(() => {
425
- rootRef.current?.measureInWindow((x, y, width, height) => {
426
- navigation.layout = { x, y, width, height }
427
- })
428
431
  const isCustom = pageConfig.navigationStyle === 'custom'
429
432
  let opt = {}
430
433
  if (__mpx_mode__ === 'android') {
@@ -451,36 +454,54 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
451
454
  })
452
455
  }, [])
453
456
 
457
+ const rootRef = useRef(null)
458
+ const onLayout = useCallback(() => {
459
+ rootRef.current?.measureInWindow((x, y, width, height) => {
460
+ navigation.layout = { x, y, width, height }
461
+ })
462
+ }, [])
463
+
454
464
  navigation.insets = useSafeAreaInsets()
455
465
 
456
466
  return createElement(GestureHandlerRootView,
457
467
  {
468
+ style: {
469
+ flex: 1
470
+ }
471
+ },
472
+ createElement(ReactNative.View, {
458
473
  style: {
459
474
  flex: 1,
460
475
  backgroundColor: pageConfig.backgroundColor || '#ffffff'
461
476
  },
462
- ref: rootRef
477
+ ref: rootRef,
478
+ onLayout
463
479
  },
464
- // todo custom portal host for active route
465
- createElement(Provider,
466
- null,
467
- createElement(RouteContext.Provider,
468
- {
469
- value: currentPageId
470
- },
471
- createElement(defaultOptions,
480
+ createElement(Provider,
481
+ null,
482
+ createElement(RouteContext.Provider,
472
483
  {
473
- navigation,
474
- route,
475
- id: currentPageId
476
- }
484
+ value: currentPageId
485
+ },
486
+ createElement(IntersectionObserverContext.Provider,
487
+ {
488
+ value: intersectionObservers.current
489
+ },
490
+ createElement(defaultOptions,
491
+ {
492
+ navigation,
493
+ route,
494
+ id: currentPageId
495
+ }
496
+ )
497
+ )
477
498
  )
478
499
  )
479
500
  )
501
+ // todo custom portal host for active route
480
502
  )
481
503
  }
482
504
  return Page
483
505
  }
484
-
485
506
  return defaultOptions
486
507
  }
@@ -23,11 +23,13 @@ function transformProperties (properties) {
23
23
  } else {
24
24
  newFiled = Object.assign({}, rawFiled)
25
25
  }
26
- newFiled.observer = function (value) {
26
+ const rawObserver = rawFiled?.observer
27
+ newFiled.observer = function (value, oldValue) {
27
28
  if (this.__mpxProxy) {
28
29
  this[key] = value
29
30
  this.__mpxProxy.propsUpdated()
30
31
  }
32
+ rawObserver && rawObserver.call(this, value, oldValue)
31
33
  }
32
34
  newProps[key] = newFiled
33
35
  })