Skip to content
This repository has been archived by the owner on Mar 7, 2024. It is now read-only.

Commit

Permalink
fix: 修复节点卸载后回调没从 Page 上删除的问题 (#1822)
Browse files Browse the repository at this point in the history
close #1780
  • Loading branch information
yesmeck committed Jan 11, 2022
1 parent e7750fd commit 0a10885
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 11 deletions.
4 changes: 4 additions & 0 deletions packages/remax-runtime/src/Container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ export default class Container {
};
}

removeCallback(name: string) {
delete this.context[name];
}

appendChild(child: VNode) {
this.root.appendChild(child);
}
Expand Down
18 changes: 17 additions & 1 deletion packages/remax-runtime/src/VNode.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import propsAlias, { propAlias } from './propsAlias';
import { TYPE_TEXT } from './constants';
import { REMAX_METHOD, TYPE_TEXT } from './constants';
import Container from './Container';
import { RuntimeOptions } from '@remax/framework-shared';
import { createCallbackProxy } from './SyntheticEvent/createCallbackProxy';

export interface RawNode {
id: number;
Expand Down Expand Up @@ -48,6 +49,7 @@ export default class VNode {
previousSibling: VNode | null = null;
nextSibling: VNode | null = null;
text?: string;
callbackIds = new Set<string>();

constructor({ id, type, props, container }: { id: number; type: string; props?: any; container: any }) {
this.id = id;
Expand Down Expand Up @@ -117,6 +119,7 @@ export default class VNode {
node.previousSibling = null;
node.nextSibling = null;
node.deleted = true;
node.unregisteredCallbacks();

if (this.isMounted()) {
this.container.requestUpdate({
Expand Down Expand Up @@ -259,6 +262,19 @@ export default class VNode {
return this.deleted === true ? this.deleted : this.parent?.isDeleted() ?? false;
}

registerCallback(propKey: string, propValue: any) {
const id = `${REMAX_METHOD}_${this.id}_${propKey}`;
this.callbackIds.add(id);
this.container.createCallback(id, createCallbackProxy(propKey, this, propValue));
return id;
}

unregisteredCallbacks() {
this.callbackIds.forEach(id => {
this.container.removeCallback(id);
});
}

toJSON() {
const stack: Array<{
currentNode: RawNode;
Expand Down
34 changes: 34 additions & 0 deletions packages/remax-runtime/src/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { reset as resetInstanceId } from '../instanceId';
import Container from '../Container';
import { useNativeEffect } from '../hooks';
import { RuntimeOptions } from '@remax/framework-shared';
import { REMAX_METHOD } from '../constants';

function delay(ms: number): Promise<void> {
if (typeof ms !== 'number') {
Expand Down Expand Up @@ -363,6 +364,39 @@ describe('ali remax render', () => {
done();
}, 100);
});

it('remove event listener when unmount', () => {
class Page extends React.Component<{ node: any }> {
state = {
show: true,
};

hide() {
this.setState({ show: false });
}

render() {
return (
<View>
{this.state.show && (
<View ref={this.props.node} onClick={() => console.log('hello')}>
foo
</View>
)}
</View>
);
}
}
const container = new Container(p);
const page = React.createRef<any>();
const node = React.createRef<any>();
render(<Page ref={page} node={node} />, container);
const nodeId = node.current.id;
const contextKey = `${REMAX_METHOD}_${nodeId}_onClick`;
expect(container.context[contextKey]).toBeTruthy();
page.current.hide();
expect(container.context[contextKey]).toBeUndefined();
});
});

it('create proxy for onClick callback', () => {
Expand Down
19 changes: 9 additions & 10 deletions packages/remax-runtime/src/hostConfig/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import * as scheduler from 'scheduler';
import { REMAX_METHOD, TYPE_TEXT } from '../constants';
import { TYPE_TEXT } from '../constants';
import { generate } from '../instanceId';
import VNode from '../VNode';
import Container from '../Container';
import { createCallbackProxy } from '../SyntheticEvent/createCallbackProxy';
import diffProperties from './diffProperties';

const {
Expand All @@ -19,13 +18,13 @@ const DOM_TAG_MAP: { [name: string]: string } = {
img: 'image',
};

function processProps(newProps: any, node: VNode, id: number) {
function processProps(newProps: any, node: VNode) {
const props: any = {};
node.unregisteredCallbacks();
for (const propKey of Object.keys(newProps)) {
if (typeof newProps[propKey] === 'function') {
const contextKey = `${REMAX_METHOD}_${id}_${propKey}`;
node.container.createCallback(contextKey, createCallbackProxy(propKey, node, newProps[propKey]));
props[propKey] = contextKey;
const id = node.registerCallback(propKey, newProps[propKey]);
props[propKey] = id;
} else if (propKey === 'style') {
props[propKey] = newProps[propKey] || '';
} else if (propKey === 'children') {
Expand Down Expand Up @@ -84,7 +83,7 @@ export default {
props: {},
container,
});
node.props = processProps(newProps, node, id);
node.props = processProps(newProps, node);

return node;
},
Expand All @@ -109,14 +108,14 @@ export default {
},

prepareUpdate(node: VNode, type: string, lastProps: any, nextProps: any) {
lastProps = processProps(lastProps, node, node.id);
nextProps = processProps(nextProps, node, node.id);
lastProps = processProps(lastProps, node);
nextProps = processProps(nextProps, node);

return diffProperties(lastProps, nextProps);
},

commitUpdate(node: VNode, updatePayload: any, type: string, oldProps: any, newProps: any) {
node.props = processProps(newProps, node, node.id);
node.props = processProps(newProps, node);
node.update(updatePayload);
},

Expand Down

0 comments on commit 0a10885

Please sign in to comment.