Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat]rn-relatons #1679

Merged
merged 19 commits into from
Jan 21, 2025
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/core/src/convertor/wxToReact.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
import { implemented } from '../core/implement'

// 暂不支持的wx选项,后期需要各种花式支持
const unsupported = ['relations', 'moved', 'definitionFilter']
const unsupported = ['moved', 'definitionFilter']

function convertErrorDesc (key) {
error(`Options.${key} is not supported in runtime conversion from wx to react native.`, global.currentResource)
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/platform/builtInMixins/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ export default function getBuiltInMixins ({ type, rawOptions = {} }) {
directiveHelperMixin(),
styleHelperMixin(),
refsMixin(),
i18nMixin()
i18nMixin(),
relationsMixin(type)
]
} else if (__mpx_mode__ === 'web') {
bulitInMixins = [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import relationsMixin from './relationsMixin.ios'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

现在不需要加这个额外的.android了,文件条件编译找不到.android会自动去找.ios

export default relationsMixin
83 changes: 83 additions & 0 deletions packages/core/src/platform/builtInMixins/relationsMixin.ios.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { BEFORECREATE, MOUNTED, BEFOREUNMOUNT } from '../../core/innerLifecycle'

const relationTypeMap = {
parent: 'child',
ancestor: 'descendant'
}

export default function relationsMixin (mixinType) {
if (mixinType === 'component') {
return {
[BEFORECREATE] () {
this.__mpxRelations = {}
this.__mpxRelationNodesMap = {}
},
[MOUNTED] () {
this.__mpxCollectRelations()
this.__mpxExecRelations('linked')
},
[BEFOREUNMOUNT] () {
this.__mpxExecRelations('unlinked')
this.__mpxRelations = {}
this.__mpxRelationNodesMap = {}
},
methods: {
getRelationNodes (path) {
return this.__mpxRelationNodesMap[path] || null
},
__mpxCollectRelations () {
Copy link
Collaborator

@hiyuki hiyuki Jan 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

感觉这个循环还有this.__mpxRelations有点多余,如果下面的this.__relation是按需生成的这里可以省略很多逻辑

const relations = this.__mpxProxy.options.relations
if (!relations) return
Object.keys(relations).forEach(path => {
const relation = relations[path]
this.__mpxCheckParent(this, relation, path)
})
},
__mpxCheckParent (current, relation, path) {
const type = relation.type
const relationMap = current.__relation
if (!relationMap) return

if (relationMap[path]) {
const target = relationMap[path]
const targetRelation = target.__mpxProxy.options.relations?.[this.__componentPath]
if (targetRelation && targetRelation.type === relationTypeMap[type] && target.__componentPath) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

target.__componentPath 这个判断为啥需要

this.__mpxRelations[path] = {
target,
targetRelation,
relation
}
this.__mpxRelationNodesMap[path] = [target]
}
}
},
__mpxExecRelations (type) {
Object.keys(this.__mpxRelations).forEach(path => {
const { target, targetRelation, relation } = this.__mpxRelations[path]
const currentPath = this.__componentPath
if (type === 'linked') {
this.__mpxLinkRelationNodes(target, currentPath)
} else if (type === 'unlinked') {
this.__mpxRemoveRelationNodes(target, currentPath)
}
if (typeof targetRelation[type] === 'function') {
targetRelation[type].call(target, this)
}
if (typeof relation[type] === 'function') {
relation[type].call(this, target)
}
})
},
__mpxLinkRelationNodes (target, path) {
target.__mpxRelationNodesMap[path] = target.__mpxRelationNodesMap[path] || [] // 父级绑定子级
target.__mpxRelationNodesMap[path].push(this)
},
__mpxRemoveRelationNodes (target, path) {
const arr = target.__mpxRelationNodesMap[path] || []
const index = arr.indexOf(this)
if (index !== -1) arr.splice(index, 1)
}
}
}
}
}
60 changes: 55 additions & 5 deletions packages/core/src/platform/patch/getDefaultOptions.ios.js
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -193,7 +193,7 @@ const instanceProto = {
}
}

function createInstance ({ propsRef, type, rawOptions, currentInject, validProps, components, pageId, intersectionCtx }) {
function createInstance ({ propsRef, type, rawOptions, currentInject, validProps, components, pageId, intersectionCtx, relation }) {
const instance = Object.create(instanceProto, {
dataset: {
get () {
Expand Down Expand Up @@ -233,6 +233,18 @@ function createInstance ({ propsRef, type, rawOptions, currentInject, validProps
},
enumerable: false
},
__componentPath: {
get () {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里也限定组件再挂载吧,否则会取到其他组件的值很奇怪

return currentInject.componentPath || ''
},
enumerable: false
},
__relation: {
get () {
return relation
},
enumerable: false
},
__injectedRender: {
get () {
return currentInject.render || noop
Expand Down Expand Up @@ -374,6 +386,43 @@ function usePageStatus (navigation, pageId) {
}, [navigation])
}

const RelationsContext = createContext(null)

const needRelationContext = (options) => {
const relations = options.relations
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

relations的分析可以createComponent里做完直接存在闭包里,没有必要在render里做

if (!relations) return false
return Object.keys(relations).some((path) => {
const relation = relations[path]
const type = relation.type
return type === 'child' || type === 'descendant'
})
}

const provideRelation = (instance) => {
const componentPath = instance.__componentPath
const relation = instance.__relation
if (relation) {
if (!relation[componentPath]) {
relation[componentPath] = instance
}
return relation
} else {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

需要返回一个新对象,而不是修改原有对象

return {
[componentPath]: instance
}
}
}

const wrapRelationProvider = (element, instance) => {
if (needRelationContext(instance.__mpxProxy.options)) {
return createElement(RelationsContext.Provider, {
value: provideRelation(instance)
}, element)
} else {
return element
}
}

export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
rawOptions = mergeOptions(rawOptions, type, false)
const components = Object.assign({}, rawOptions.components, currentInject.getComponents())
Expand All @@ -384,11 +433,12 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
const propsRef = useRef(null)
const intersectionCtx = useContext(IntersectionObserverContext)
const pageId = useContext(RouteContext)
const relation = useContext(RelationsContext)
propsRef.current = props
Copy link
Collaborator

@hiyuki hiyuki Jan 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

解析放到mount中进行,render中简单透传relation即可

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if(hasDescendantRelation || hasAncestorRelation) {
relation = useContext(RelationsContext)
}

let isFirst = false
if (!instanceRef.current) {
isFirst = true
instanceRef.current = createInstance({ propsRef, type, rawOptions, currentInject, validProps, components, pageId, intersectionCtx })
instanceRef.current = createInstance({ propsRef, type, rawOptions, currentInject, validProps, components, pageId, intersectionCtx, relation })
}
const instance = instanceRef.current
useImperativeHandle(ref, () => {
Expand Down Expand Up @@ -472,9 +522,9 @@ 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 wrapRelationProvider(cloneElement(root, rootProps), instance)
}
return root
return wrapRelationProvider(root, instance)
}))

if (rawOptions.options?.isCustomText) {
Expand Down
3 changes: 2 additions & 1 deletion packages/webpack-plugin/lib/react/processScript.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module.exports = function (script, {
moduleId,
isProduction,
jsonConfig,
outputPath,
builtInComponentsMap,
localComponentsMap,
localPagesMap
Expand Down Expand Up @@ -64,7 +65,7 @@ global.__navigationHelper = {
jsonConfig
})

output += buildGlobalParams({ moduleId, scriptSrcMode, loaderContext, isProduction, ctorType, jsonConfig, componentsMap })
output += buildGlobalParams({ moduleId, scriptSrcMode, loaderContext, isProduction, ctorType, jsonConfig, componentsMap, outputPath })
output += getRequireScript({ ctorType, script, loaderContext })
output += `export default global.__mpxOptionsMap[${JSON.stringify(moduleId)}]\n`
}
Expand Down
6 changes: 5 additions & 1 deletion packages/webpack-plugin/lib/react/script-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ function buildGlobalParams ({
jsonConfig,
componentsMap,
pagesMap,
firstPage
firstPage,
outputPath
}) {
let content = ''
if (ctorType === 'app') {
Expand Down Expand Up @@ -117,6 +118,9 @@ global.currentInject.firstPage = ${JSON.stringify(firstPage)}\n`
content += `global.currentInject.getComponents = function () {
return ${shallowStringify(componentsMap)}
}\n`
if (ctorType === 'component') {
content += `global.currentInject.componentPath = '/' + ${JSON.stringify(outputPath)}\n`
}
}
content += `global.currentModuleId = ${JSON.stringify(moduleId)}\n`
content += `global.currentSrcMode = ${JSON.stringify(scriptSrcMode)}\n`
Expand Down
Loading