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

Commit

Permalink
fix(wechat): 修复更新已删除的节点导致报错的问题 (#1078)
Browse files Browse the repository at this point in the history
close #1065
  • Loading branch information
yesmeck committed Jun 15, 2020
1 parent 52cd82f commit 84f45fa
Show file tree
Hide file tree
Showing 4 changed files with 216 additions and 15 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions packages/remax-runtime/src/Container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export default class Container {
context: any;
root: VNode;
updateQueue: Array<SpliceUpdate | SetUpdate> = [];
deletedPaths = new Set<string>();
_rootContainer?: FiberRoot;
stopUpdate?: boolean;
rendered = false;
Expand All @@ -41,12 +42,18 @@ export default class Container {

requestUpdate(update: SpliceUpdate | SetUpdate, immediately?: boolean) {
if (immediately) {
if ((update as SpliceUpdate).deleteCount === 1) {
this.deletedPaths.add(update.path);
}
this.updateQueue.push(update);
this.applyUpdate();
} else {
if (this.updateQueue.length === 0) {
Promise.resolve().then(() => this.applyUpdate());
}
if ((update as SpliceUpdate).deleteCount === 1) {
this.deletedPaths.add(update.path);
}
this.updateQueue.push(update);
}
}
Expand Down Expand Up @@ -101,11 +108,19 @@ export default class Container {
});

this.updateQueue = [];
this.deletedPaths.clear();

return;
}

const updatePayload = this.updateQueue.reduce<{ [key: string]: any }>((acc, update) => {
// 如果父元素已经删除了,跳过所有对其子元素的操作
for (const deletedPath of this.deletedPaths) {
if (new RegExp(`^${deletedPath}.nodes`).test(update.path)) {
return acc;
}
}

if (update.type === 'splice') {
const item = {
...acc,
Expand Down Expand Up @@ -134,6 +149,7 @@ export default class Container {
});

this.updateQueue = [];
this.deletedPaths.clear();
}

clearUpdate() {
Expand Down
105 changes: 96 additions & 9 deletions packages/remax-runtime/src/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ import createPageWrapper from '../createPageWrapper';
// eslint-disable-next-line @typescript-eslint/camelcase
import { useNativeEffect, usePageInstance } from '../hooks';

function delay(ms: number) {
if (typeof ms !== 'number') {
throw new Error('Must specify ms');
}
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, ms);
});
}

const p = {
setData(state: any, callback: Function) {
setTimeout(() => {
Expand Down Expand Up @@ -572,18 +583,94 @@ it('usePageInstance works', done => {
render(<Page page={{ data: {} }} />, container);
});

describe('Remax Suspense placeholder', () => {
function delay(ms: number) {
if (typeof ms !== 'number') {
throw new Error('Must specify ms');
describe('wechat renderer', () => {
beforeEach(() => {
process.env.REMAX_PLATFORM = 'wechat';
resetInstanceId();
});

afterEach(() => {
process.env.REMAX_PLATFORM = '';
});

it("does not update deleted node's children node", async () => {
const logs: any = [];
class App extends React.Component {
state = {
a: true,
b: true,
};

toggle() {
this.setState({
b: false,
});
this.setState({
a: false,
});
}

render() {
const { a, b } = this.state;
return <View id="a">{a && <View id="b">{b ? <View id="c">a</View> : 'b'}</View>}</View>;
}
}
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, ms);

const container = new Container({
setData(action: any) {
logs.push(action);
},
});
}
const app = React.createRef<any>();
render(<App ref={app} />, container);
app.current.toggle();
await delay(100);
expect(logs.pop()).toEqual({
'root.nodes.4.children': [],
'root.nodes.4.nodes.3': null,
});
});

it('does not update deleted node', async () => {
const logs: any = [];
class App extends React.Component {
state = {
a: true,
b: true,
};

toggle() {
this.setState({
b: false,
});
this.setState({
a: false,
});
}

render() {
const { a, b } = this.state;
return <View>{a && <View style={{ color: b ? 'red' : 'green' }}>foo</View>}</View>;
}
}

const container = new Container({
setData(action: any) {
logs.push(action);
},
});
const app = React.createRef<any>();
render(<App ref={app} />, container);
app.current.toggle();
await delay(100);
expect(logs.pop()).toEqual({
'root.nodes.3.children': [],
'root.nodes.3.nodes.2': null,
});
});
});

describe('Remax Suspense placeholder', () => {
function createTextResource(ms: number, text: string) {
let status = 'pending';
let result: any;
Expand Down

1 comment on commit 84f45fa

@vercel
Copy link

@vercel vercel bot commented on 84f45fa Jun 15, 2020

Choose a reason for hiding this comment

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

Please sign in to comment.