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: renderClient with callback #4979

Merged
merged 10 commits into from
Jul 27, 2020
3 changes: 2 additions & 1 deletion packages/preset-built-in/src/plugins/generateFiles/umi.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ import { renderClient } from '{{{ rendererPath }}}';
const getClientRender = (args: { hot?: boolean } = {}) => plugin.applyPlugins({
key: 'render',
type: ApplyPluginsType.compose,
initialValue: () => {
initialValue: (opts = {}) => {
kuitos marked this conversation as resolved.
Show resolved Hide resolved
return renderClient({
...opts,
Copy link
Member

Choose a reason for hiding this comment

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

https://github.com/umijs/umi/pull/5067/files 里的变更好像重复了

...opts 挪到最下面?相对于允许覆盖默认配置

Copy link
Contributor Author

Choose a reason for hiding this comment

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

不建议覆盖默认的值,...opts 问题排查起来比较麻烦

kuitos marked this conversation as resolved.
Show resolved Hide resolved
// @ts-ignore
routes: require('./core/routes').routes,
plugin,
Expand Down
66 changes: 65 additions & 1 deletion packages/renderer-react/src/renderClient/renderClient.test.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
import React from 'react';
import { render, cleanup, waitFor, getByText } from '@testing-library/react';
import { act } from 'react-dom/test-utils';
ycjcl868 marked this conversation as resolved.
Show resolved Hide resolved
import { createMemoryHistory, Plugin, dynamic } from '@umijs/runtime';
import renderClient, { preloadComponent } from './renderClient';

afterEach(cleanup);
let container;
beforeEach(() => {
container = document.createElement('div');
container.id = 'app';
document.body.appendChild(container);
});

afterEach(() => {
document.body.removeChild(container);
container = null;
cleanup();
});

test('normal', async () => {
const history = createMemoryHistory({
Expand Down Expand Up @@ -49,6 +61,58 @@ test('normal', async () => {
expect(routeChanges).toEqual(['POP /foo', 'PUSH /bar']);
});

test('normal with mount', async () => {
const history = createMemoryHistory({
initialEntries: ['/foo'],
});
const routeChanges: string[] = [];
const plugin = new Plugin({
validKeys: ['onRouteChange', 'rootContainer'],
});
plugin.register({
apply: {
onRouteChange({ location, action }: any) {
routeChanges.push(`${action} ${location.pathname}`);
},
rootContainer(container: any, args: any) {
if (!(args.history && args.plugin && args.routes)) {
throw new Error(
'history, plugin or routes not exists in the args of rootContainer',
);
}
return <div>{container}</div>;
},
},
path: '/foo',
});
let loading = true;
act(() => {
renderClient({
history,
plugin,
// #app
rootElement: 'app',
routes: [
{ path: '/foo', component: () => <h1>foo</h1> },
{ path: '/bar', component: () => <h1>bar</h1> },
],
callback: () => {
loading = false;
},
});
});
expect(container.outerHTML).toEqual(
'<div id="app"><div><h1>foo</h1></div></div>',
);
expect(loading).toBeFalsy();

history.push({
pathname: '/bar',
});
expect(container.innerHTML).toEqual('<div><h1>bar</h1></div>');
expect(routeChanges).toEqual(['POP /foo', 'PUSH /bar']);
});

const Common = ({ title }) => {
return <h1>{title}</h1>;
};
Expand Down
11 changes: 7 additions & 4 deletions packages/renderer-react/src/renderClient/renderClient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ interface IRouterComponentProps {

interface IOpts extends IRouterComponentProps {
rootElement?: string | HTMLElement;
callback?: () => void;
}

function RouterComponent(props: IRouterComponentProps) {
Expand Down Expand Up @@ -111,19 +112,21 @@ export default function renderClient(opts: IOpts) {
typeof opts.rootElement === 'string'
? document.getElementById(opts.rootElement)
: opts.rootElement;
// flag showing SSR successed
const callback = opts.callback || (() => {});
ycjcl868 marked this conversation as resolved.
Show resolved Hide resolved

// flag showing SSR successed
if (window.g_useSSR) {
if (opts.dynamicImport) {
// dynamicImport should preload current route component
// first loades);
preloadComponent(opts.routes).then(function () {
ReactDOM.hydrate(rootContainer, rootElement);
ReactDOM.hydrate(rootContainer, rootElement, callback);
});
} else {
ReactDOM.hydrate(rootContainer, rootElement);
ReactDOM.hydrate(rootContainer, rootElement, callback);
}
} else {
ReactDOM.render(rootContainer, rootElement);
ReactDOM.render(rootContainer, rootElement, callback);
}
} else {
return rootContainer;
Expand Down