Marko support rerendering (#7460)

Marko support rerendering
This commit is contained in:
Michael Shilman 2019-07-20 01:07:03 +08:00 committed by GitHub
commit 0d872f723d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 65 additions and 32 deletions

View File

@ -2,7 +2,8 @@ import { document } from 'global';
import { stripIndents } from 'common-tags';
const rootEl = document.getElementById('root');
let currLoadedComponent = null; // currently loaded marko widget!
let activeComponent = null; // currently loaded marko component.
let activeTemplate = null; // template for the currently loaded component.
export default function renderMain({
storyFn,
@ -10,26 +11,52 @@ export default function renderMain({
selectedStory,
showMain,
showError,
parameters,
// forceRender,
}) {
const element = storyFn();
const config = storyFn();
// We need to unmount the existing set of components in the DOM node.
if (currLoadedComponent) {
currLoadedComponent.destroy();
}
if (!element || !element.out) {
if (!config || !(config.appendTo || config.component || parameters.component)) {
showError({
title: `Expecting a Marko element from the story: "${selectedStory}" of "${selectedKind}".`,
title: `Expecting an object with a component property to be returned from the story: "${selectedStory}" of "${selectedKind}".`,
description: stripIndents`
Did you forget to return the Marko element from the story?
Use "() => MyComp.renderSync({})" or "() => { return MyComp.renderSync({}); }" when defining the story.
Did you forget to return the component from the story?
Use "() => ({ component: MyComponent, input: { hello: 'world' } })" when defining the story.
`,
});
return;
}
if (config.appendTo) {
console.warn(
'@storybook/marko: returning a rendered component for a story is deprecated, return an object with `{ component, input }` instead.'
);
// The deprecated API always destroys the previous component instance.
if (activeComponent) {
activeComponent.destroy();
}
activeComponent = config.appendTo(rootEl).getComponent();
} else {
const template = config.component || parameters.component;
if (activeTemplate === template) {
// When rendering the same template with new input, we reuse the same instance.
activeComponent.input = config.input;
activeComponent.update();
} else {
if (activeComponent) {
activeComponent.destroy();
}
activeTemplate = template;
activeComponent = activeTemplate
.renderSync(config.input)
.appendTo(rootEl)
.getComponent();
}
}
showMain();
currLoadedComponent = element.appendTo(rootEl).getComponent();
}

View File

@ -88,15 +88,18 @@ That'll load stories in `../stories/index.js`. You can choose where to place sto
Now create a `../stories/index.js` file, and write your first story like this:
```js
/** @jsx m */
import m from 'marko';
import { storiesOf } from '@storybook/marko';
import Button from '../components/button/index.marko';
storiesOf('Button', module)
.add('with text', () => Button.renderSync({ text: 'some text'}))
.add('with emoji', () => Button.renderSync({ text: '😀 😎 👍 💯'}));
.add('with text', () => ({
component: Button,
input: { text 'some text' }
}))
.add('with emoji', () => ({
component: Button,
input: { text '😀 😎 👍 💯' }
}));
```
Each story is a single state of your component. In the above case, there are two stories for the demo button component:

View File

@ -5,7 +5,13 @@ export default {
title: 'Addons|Actions/Button',
parameters: {
component: Button,
options: {
panelPosition: 'right',
},
},
};
export const Simple = () => Button.renderSync({ click: action('action logged!') });
export const Simple = () => ({
component: Button,
input: { click: action('action logged!') },
});

View File

@ -10,11 +10,9 @@ export default {
},
};
export const Simple = () => {
const name = text('Name', 'John Doe');
const age = number('Age', 44);
return Hello.renderSync({
name,
age,
});
};
export const Simple = () => ({
input: {
name: text('Name', 'John Doe'),
age: number('Age', 44),
},
});

View File

@ -2,10 +2,9 @@ import ClickCount from '../components/click-count/index.marko';
export default {
title: 'Main|ClickCount',
parameters: {
component: ClickCount,
},
};
export const Simple = () => ClickCount.renderSync({});
export const Simple = () => ({ component: ClickCount });

View File

@ -7,6 +7,6 @@ export default {
},
};
export const Simple = () => Hello.renderSync({ name: 'abc', age: 20 });
export const Simple = () => ({ input: { name: 'abc', age: 20 } });
export const story2 = () => 'NOT A MARKO RENDER_RESULT';
story2.story = { name: 'with ERROR!' };

View File

@ -7,4 +7,4 @@ export default {
},
};
export const Simple = () => StopWatch.renderSync({});
export const Simple = () => ({ component: StopWatch });

View File

@ -7,4 +7,4 @@ export default {
},
};
export const welcome = () => Welcome.renderSync({});
export const welcome = () => ({ component: Welcome });

View File

@ -1,4 +1,4 @@
import { storiesOf } from '@storybook/marko';
import Welcome from './components/welcome/index.marko';
storiesOf('Welcome', module).add('welcome', () => Welcome.renderSync({}));
storiesOf('Welcome', module).add('welcome', () => ({ component: Welcome }));