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

Commit

Permalink
feat: 生命周期 & 交互事件支持 batchedUpdates (#1635)
Browse files Browse the repository at this point in the history
* feat: 生命周期 & 交互事件支持合并更新

close #1633

* test: batchedUpdates

* chore: update yarn.lock

* fix: type

* test: update

Co-authored-by: 农有宝 <[email protected]>
  • Loading branch information
noyobo and 农有宝 committed Jul 6, 2021
1 parent ccfbbda commit fec2741
Show file tree
Hide file tree
Showing 10 changed files with 175 additions and 25 deletions.
4 changes: 2 additions & 2 deletions packages/remax-runtime/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@
"@remax/web": "2.13.6",
"qs": "^6.9.3",
"react-is": "^16.3.1",
"react-reconciler": "0.25.1",
"react-reconciler": "0.26.2",
"scheduler": "0.19.1"
},
"devDependencies": {
"@remax/types": "2.13.6",
"@types/lodash.merge": "^4.6.6",
"@types/node": "^14.0.1",
"@types/react": "^16.9.33",
"@types/react-reconciler": "^0.18.0",
"@types/react-reconciler": "0.26.1",
"@types/react-test-renderer": "^16.9.2",
"object-path-immutable": "^4.0.2",
"react": "^16.8.6",
Expand Down
7 changes: 6 additions & 1 deletion packages/remax-runtime/src/Container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { generate } from './instanceId';
import { FiberRoot } from 'react-reconciler';
import nativeEffector from './nativeEffect';
import { RuntimeOptions } from '@remax/framework-shared';
import { unstable_batchedUpdates } from './index';

interface SpliceUpdate {
path: string[];
Expand Down Expand Up @@ -142,7 +143,11 @@ export default class Container {
}

createCallback(name: string, fn: (...params: any) => any) {
this.context[name] = fn;
this.context[name] = (...args: any) => {
return unstable_batchedUpdates(args => {
return fn(...args);
}, args);
};
}

appendChild(child: VNode) {
Expand Down
14 changes: 9 additions & 5 deletions packages/remax-runtime/src/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -367,8 +367,12 @@ describe('ali remax render', () => {

it('create proxy for onClick callback', () => {
const view = React.createRef<any>();
const handleClick = () => void 0;
const handleAnimationStart = () => void 0;
const handleClick = (event: any) => {
expect(event.stopPropagation).not.toBeUndefined();
};
const handleAnimationStart = (event: any) => {
expect(event.stopPropagation).toBeUndefined();
};
class Page extends React.Component {
render() {
return <View ref={view} onClick={handleClick} onAnimationStart={handleAnimationStart} />;
Expand All @@ -383,11 +387,11 @@ it('create proxy for onClick callback', () => {
return view.current.container.context[fnKey];
}

const newHandleClick = findFn('onTap');
const newHandleClick = findFn('onClick');
const newHandleAnimationStart = findFn('onAnimationStart');

expect(newHandleClick).not.toBe(handleClick);
expect(newHandleAnimationStart).toBe(handleAnimationStart);
newHandleClick({});
newHandleAnimationStart({});
});

it('useEffect works', done => {
Expand Down
14 changes: 9 additions & 5 deletions packages/remax-runtime/src/__tests__/index.toutiao.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,12 @@ describe('remax render', () => {

it('create proxy for onClick callback', () => {
const view = React.createRef<any>();
const handleClick = () => void 0;
const handleAnimationStart = () => void 0;
const handleClick = (event: any) => {
expect(event.stopPropagation).not.toBeUndefined();
};
const handleAnimationStart = (event: any) => {
expect(event.stopPropagation).toBeUndefined();
};
class Page extends React.Component {
render() {
return <View ref={view} onClick={handleClick} onAnimationStart={handleAnimationStart} />;
Expand All @@ -217,11 +221,11 @@ it('create proxy for onClick callback', () => {
return view.current.container.context[fnKey];
}

const newHandleClick = findFn('onTap');
const newHandleClick = findFn('onClick');
const newHandleAnimationStart = findFn('onAnimationStart');

expect(newHandleClick).not.toBe(handleClick);
expect(newHandleAnimationStart).toBe(handleAnimationStart);
newHandleClick({});
newHandleAnimationStart({});
});

it('useEffect works', done => {
Expand Down
15 changes: 10 additions & 5 deletions packages/remax-runtime/src/__tests__/index.wechat.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -372,8 +372,13 @@ describe('wechat remax render', () => {

it('create proxy for onClick callback', () => {
const view = React.createRef<any>();
const handleClick = () => void 0;
const handleAnimationStart = () => void 0;
const handleClick = (event: any) => {
expect(event.stopPropagation).not.toBeUndefined();
};
const handleAnimationStart = (event: any) => {
expect(event.stopPropagation).toBeUndefined();
};

class Page extends React.Component {
render() {
return <View ref={view} onClick={handleClick} onAnimationStart={handleAnimationStart} />;
Expand All @@ -388,11 +393,11 @@ describe('wechat remax render', () => {
return view.current.container.context[fnKey];
}

const newHandleClick = findFn('onTap');
const newHandleClick = findFn('onClick');
const newHandleAnimationStart = findFn('onAnimationStart');

expect(newHandleClick).not.toBe(handleClick);
expect(newHandleAnimationStart).toBe(handleAnimationStart);
newHandleClick({});
newHandleAnimationStart({});
});

it('useEffect works', done => {
Expand Down
104 changes: 104 additions & 0 deletions packages/remax-runtime/src/__tests__/page.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -409,4 +409,108 @@ describe('page', () => {
'componentWillUnmount',
]);
});

it('hooks methods', done => {
const log: string[] = [];
const Foo = () => {
React.useEffect(() => {
log.push('componentDidMount');
return () => {
log.push('componentWillUnmount');
expect(log).toEqual(['componentDidMount', 'componentWillUnmount']);
done();
};
}, []);
return <View>foo</View>;
};
const page = Page(createPageConfig(Foo, TEST_PAGE));
page.load();
page.unload();
});

it('call useEffect', done => {
const Foo = React.forwardRef((props, ref) => {
const log = React.useRef<string[]>([]);
const times = React.useRef(0);
const [v1, upV1] = React.useState(1);
const [v2, upV2] = React.useState(1);

React.useEffect(() => {
log.current.push('foo didMount');
return () => {
expect(times.current).toEqual(2);
expect(log.current).toEqual(['foo onShow', 'foo didMount']);
done();
};
}, []);

React.useEffect(
function updateTimes() {
times.current += 1;
},
[v1, v2]
);

usePageEvent('onShow', function updateState() {
upV1(2);
upV2(2);
log.current.push('foo onShow');
});

return <View>useEffect</View>;
});
const page = Page(createPageConfig(() => <Foo />, TEST_PAGE));
page.load();
page.unload();
});

it('call events batchedUpdates', done => {
const Foo = React.forwardRef((props, ref) => {
const log = React.useRef<string[]>([]);
const times = React.useRef(0);
const [v1, upV1] = React.useState(1);
const [v2, upV2] = React.useState(1);

const up = (event: any) => {
expect(event.stopPropagation).toBeTruthy();
upV1(2);
upV2(2);
};

React.useEffect(() => {
log.current.push('foo didMount');
return () => {
expect(times.current).toEqual(2);
expect(log.current).toEqual(['foo onShow', 'foo didMount']);
done();
};
}, []);

React.useEffect(
function updateTimes() {
times.current += 1;
},
[v1, v2]
);

usePageEvent('onShow', function updateState() {
log.current.push('foo onShow');
});

return <View onClick={up}>useEffect</View>;
});
const page = Page(createPageConfig(() => <Foo />, TEST_PAGE));
page.load();
const fnKey = Object.keys(page.config).find(key => key.endsWith('onClick')) as string;
const fn = page.config[fnKey];

fn({
stopPropagation() {
// mock event
},
});
setTimeout(() => {
page.unload();
}, 300);
});
});
5 changes: 4 additions & 1 deletion packages/remax-runtime/src/createPageConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import stopPullDownRefresh from './stopPullDownRefresh';
import Container from './Container';
import { createPortal } from './ReactPortal';
import render from './render';
import { unstable_batchedUpdates } from './index';

let idCounter = 0;

Expand Down Expand Up @@ -110,7 +111,9 @@ export default function createPageConfig(Page: React.ComponentType<any>, name: s
let result;
// 生命周期中可能改变 state 导致 callbacks 发生变化
[...callbacks].map((callback: any) => {
result = callback(...args);
result = unstable_batchedUpdates(args => {
return callback(...args);
}, args);
});
if (result) {
return result;
Expand Down
8 changes: 8 additions & 0 deletions packages/remax-runtime/src/hostConfig/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ export default {
},

prepareForCommit: () => {
return null;
},

preparePortalMount: () => {
// nothing to do
},

clearContainer: () => {
// nothing to do
},

Expand Down
2 changes: 1 addition & 1 deletion packages/remax-runtime/src/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function getPublicRootInstance(container: ReactReconciler.FiberRoot) {
export default function render(rootElement: React.ReactElement | null, container: Container | AppContainer) {
// Create a root Container if it doesnt exist
if (!container._rootContainer) {
container._rootContainer = ReactReconcilerInst.createContainer(container, false, false);
container._rootContainer = ReactReconcilerInst.createContainer(container, 0, false, null);
}

ReactReconcilerInst.updateContainer(rootElement, container._rootContainer, null, () => {
Expand Down
27 changes: 22 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3325,10 +3325,10 @@
dependencies:
"@types/react" "^16"

"@types/react-reconciler@^0.18.0":
version "0.18.0"
resolved "https://registry.yarnpkg.com/@types/react-reconciler/-/react-reconciler-0.18.0.tgz#fce2b444103f44904e73eba349ac6552e2771f64"
integrity sha512-hLVaxzL7cGgk/2C/sc8yyyvi+aeeimv7SKOFgyuPFYqNb2rnnQApHabcxo5Xp+GloUAfMe3tyQm2nkrmbLXq4w==
"@types/react-reconciler@0.26.1":
version "0.26.1"
resolved "https://registry.nlark.com/@types/react-reconciler/download/@types/react-reconciler-0.26.1.tgz#67453664cae44af30e566b440b9f21ec2f1fb041"
integrity sha1-Z0U2ZMrkSvMOVmtEC58h7C8fsEE=
dependencies:
"@types/react" "*"

Expand Down Expand Up @@ -14761,7 +14761,16 @@ react-is@^17.0.1:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339"
integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==

[email protected], react-reconciler@^0.25.1:
[email protected]:
version "0.26.2"
resolved "https://registry.nlark.com/react-reconciler/download/react-reconciler-0.26.2.tgz#bbad0e2d1309423f76cf3c3309ac6c96e05e9d91"
integrity sha1-u60OLRMJQj92zzwzCaxsluBenZE=
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
scheduler "^0.20.2"

react-reconciler@^0.25.1:
version "0.25.1"
resolved "https://registry.yarnpkg.com/react-reconciler/-/react-reconciler-0.25.1.tgz#f9814d59d115e1210762287ce987801529363aaa"
integrity sha512-R5UwsIvRcSs3w8n9k3tBoTtUHdVhu9u84EG7E5M0Jk9F5i6DA1pQzPfUZd6opYWGy56MJOtV3VADzy6DRwYDjw==
Expand Down Expand Up @@ -15558,6 +15567,14 @@ [email protected], scheduler@^0.19.1:
loose-envify "^1.1.0"
object-assign "^4.1.1"

scheduler@^0.20.2:
version "0.20.2"
resolved "https://registry.nlark.com/scheduler/download/scheduler-0.20.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fscheduler%2Fdownload%2Fscheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91"
integrity sha1-S67jlDbjSqk7SHS93L8P6Li1DpE=
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"

[email protected]:
version "2.7.0"
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.0.tgz#17151f76d8eae67fbbf77960c33c676ad9f4efc7"
Expand Down

0 comments on commit fec2741

Please sign in to comment.