-
Notifications
You must be signed in to change notification settings - Fork 381
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
[feat]rn-relatons #1679
Changes from 2 commits
503e927
4418593
4ded781
a2fd798
c5fe79c
a215026
a998767
6f6774d
c44dc0c
9cecc80
0f7fc85
d3ccb55
6ec95f0
81e85fe
5bf606f
f227571
64853bb
c7d477d
41a8415
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
import relationsMixin from './relationsMixin.ios' | ||
export default relationsMixin |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
import { BEFORECREATE, MOUNTED, BEFOREUNMOUNT } from '../../core/innerLifecycle' | ||
import { isArray } from '@mpxjs/utils' | ||
|
||
const relationTypeMap = { | ||
parent: 'child', | ||
ancestor: 'descendant' | ||
} | ||
|
||
const isChildNode = (target, instance) => { | ||
let children = target.props.children | ||
if (!children) return | ||
if (!isArray(children)) { | ||
children = [children] | ||
} | ||
return children.some((item = {}) => { | ||
if (item.type?.__mpxBuiltIn) { // 如果是基础节点,继续向下查找 | ||
return isChildNode(item, instance) | ||
} else { | ||
return item.type === instance.__getReactFunctionComponent() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 光凭这个ctor也没办法判断当前的instance一定是child吧 |
||
} | ||
}) | ||
} | ||
|
||
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 () { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 target = current.__getRelation() | ||
if (!target) return | ||
|
||
// parent 只需要处理一层,ancestor 需要考虑多个层级 | ||
if ((type === 'parent' && isChildNode(target, this)) || type === 'ancestor') { | ||
const targetRelation = target.__mpxProxy.options.relations?.[this.__componentPath] | ||
if (targetRelation && targetRelation.type === relationTypeMap[type] && target.__componentPath === path) { | ||
this.__mpxRelations[path] = { | ||
target, | ||
targetRelation, | ||
relation | ||
} | ||
this.__mpxRelationNodesMap[path] = [target] | ||
} else if (type === 'ancestor') { | ||
this.__mpxCheckParent(target, relation, path) | ||
} | ||
} | ||
}, | ||
__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) | ||
} | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -68,14 +68,20 @@ function getRootProps (props) { | |
return rootProps | ||
} | ||
|
||
function createInstance ({ propsRef, type, rawOptions, currentInject, validProps, components, pageId }) { | ||
function createInstance ({ propsRef, type, rawOptions, currentInject, validProps, components, pageId, relation, reactFunctionComponent }) { | ||
const instance = Object.create({ | ||
setData (data, callback) { | ||
return this.__mpxProxy.forceUpdate(data, { sync: true }, callback) | ||
}, | ||
getPageId () { | ||
return pageId | ||
}, | ||
__getRelation () { | ||
return relation | ||
}, | ||
__getReactFunctionComponent () { | ||
return reactFunctionComponent | ||
}, | ||
__getProps () { | ||
const props = propsRef.current | ||
const propsData = {} | ||
|
@@ -127,6 +133,7 @@ function createInstance ({ propsRef, type, rawOptions, currentInject, validProps | |
} | ||
return null | ||
}, | ||
__componentPath: currentInject.componentPath, | ||
__injectedRender: currentInject.render || noop, | ||
__getRefsData: currentInject.getRefsData || noop, | ||
// render helper | ||
|
@@ -342,19 +349,33 @@ function usePageStatus (navigation, pageId) { | |
}, [navigation]) | ||
} | ||
|
||
const needRelationContext = (options) => { | ||
const relations = options.relations | ||
if (!relations) return false | ||
return Object.keys(relations).some(path => { | ||
const relation = relations[path] | ||
const type = relation.type | ||
return type === 'child' || type === 'descendant' | ||
}) | ||
} | ||
|
||
const RelationsContext = createContext(null) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. context可以以outputPath为key存一系列 |
||
|
||
export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) { | ||
rawOptions = mergeOptions(rawOptions, type, false) | ||
const components = Object.assign({}, rawOptions.components, currentInject.getComponents()) | ||
const validProps = Object.assign({}, rawOptions.props, rawOptions.properties) | ||
const defaultOptions = memo(forwardRef((props, ref) => { | ||
const instanceRef = useRef(null) | ||
const propsRef = useRef(null) | ||
const reactFunctionComponent = defaultOptions | ||
const pageId = useContext(RouteContext) | ||
const relation = useContext(RelationsContext) | ||
propsRef.current = props | ||
let isFirst = false | ||
if (!instanceRef.current) { | ||
isFirst = true | ||
instanceRef.current = createInstance({ propsRef, type, rawOptions, currentInject, validProps, components, pageId }) | ||
instanceRef.current = createInstance({ propsRef, type, rawOptions, currentInject, validProps, components, pageId, relation, reactFunctionComponent }) | ||
} | ||
const instance = instanceRef.current | ||
useImperativeHandle(ref, () => { | ||
|
@@ -403,7 +424,17 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) { | |
|
||
useSyncExternalStore(proxy.subscribe, proxy.getSnapshot) | ||
|
||
const root = rawOptions.options?.disableMemo ? proxy.effect.run() : useMemo(() => proxy.effect.run(), [proxy.stateVersion]) | ||
const runRenderEffect = () => { | ||
if (needRelationContext(rawOptions)) { | ||
return createElement(RelationsContext.Provider, { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 直接包在root上就可以了吧 |
||
value: instance | ||
}, proxy.effect.run()) | ||
} | ||
|
||
return proxy.effect.run() | ||
} | ||
|
||
const root = rawOptions.options?.disableMemo ? runRenderEffect() : useMemo(runRenderEffect, [proxy.stateVersion]) | ||
if (root) { | ||
const rootProps = getRootProps(props) | ||
rootProps.style = { ...root.props.style, ...rootProps.style } | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -88,7 +88,8 @@ function buildGlobalParams ({ | |
jsonConfig, | ||
componentsMap, | ||
pagesMap, | ||
firstPage | ||
firstPage, | ||
outputPath | ||
}) { | ||
let content = '' | ||
if (ctorType === 'app') { | ||
|
@@ -117,6 +118,7 @@ global.currentInject.firstPage = ${JSON.stringify(firstPage)}\n` | |
content += `global.currentInject.getComponents = function () { | ||
return ${shallowStringify(componentsMap)} | ||
}\n` | ||
content += `global.currentInject.componentPath = '/' + ${JSON.stringify(outputPath)}\n` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 页面是不是不用注入 |
||
} | ||
content += `global.currentModuleId = ${JSON.stringify(moduleId)}\n` | ||
content += `global.currentSrcMode = ${JSON.stringify(scriptSrcMode)}\n` | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
现在不需要加这个额外的.android了,文件条件编译找不到.android会自动去找.ios