From be2037f8d36e04a34b9af0ad1e7c76baf7fd6c35 Mon Sep 17 00:00:00 2001 From: Igor Date: Tue, 20 Nov 2018 11:52:25 +0200 Subject: [PATCH] Merge pull request #4773 from storybooks/vue-knobs-optimize-on-force-render Vue / Knobs - optimize on force render --- app/react/src/client/preview/render.js | 2 +- app/vue/src/client/preview/render.js | 41 ++++++++++++++----- .../addon-knobs.stories.storyshot | 2 +- .../src/stories/addon-knobs.stories.js | 30 ++++++++++---- 4 files changed, 55 insertions(+), 20 deletions(-) diff --git a/app/react/src/client/preview/render.js b/app/react/src/client/preview/render.js index 507e5868563..90dda3f2dba 100644 --- a/app/react/src/client/preview/render.js +++ b/app/react/src/client/preview/render.js @@ -46,7 +46,7 @@ export default function renderMain({ } // We need to unmount the existing set of components in the DOM node. - // Otherwise, React may not recrease instances for every story run. + // Otherwise, React may not recreate instances for every story run. // This could leads to issues like below: // https://github.com/storybooks/react-storybook/issues/81 // But forceRender means that it's the same story, so we want too keep the state in that case. diff --git a/app/vue/src/client/preview/render.js b/app/vue/src/client/preview/render.js index f6a4dbf0918..7204bfccae6 100644 --- a/app/vue/src/client/preview/render.js +++ b/app/vue/src/client/preview/render.js @@ -1,12 +1,26 @@ import { stripIndents } from 'common-tags'; import Vue from 'vue'; -let app = null; +let root = null; -function renderRoot(options) { - if (app) app.$destroy(); +function getComponentProxy(component) { + return Object.entries(component.props || {}) + .map(([name, def]) => ({ [name]: def.default })) + .reduce((wrap, prop) => ({ ...wrap, ...prop }), {}); +} - app = new Vue(options); +function renderRoot(component, proxy) { + root = new Vue({ + el: '#root', + beforeCreate() { + this.proxy = proxy; + }, + + render(h) { + const props = this.proxy; + return h('div', { attrs: { id: 'root' } }, [h(component, { props })]); + }, + }); } export default function render({ @@ -16,6 +30,7 @@ export default function render({ showMain, showError, showException, + forceRender, }) { Vue.config.errorHandler = showException; @@ -33,10 +48,16 @@ export default function render({ } showMain(); - renderRoot({ - el: '#root', - render(h) { - return h('div', { attrs: { id: 'root' } }, [h(component)]); - }, - }); + + const proxy = getComponentProxy(component); + + // at component creation || refresh by HMR + if (!root || !forceRender) { + if (root) root.$destroy(); + + renderRoot(component, proxy); + } else { + root.proxy = proxy; + root.$forceUpdate(); + } } diff --git a/examples/vue-kitchen-sink/src/stories/__snapshots__/addon-knobs.stories.storyshot b/examples/vue-kitchen-sink/src/stories/__snapshots__/addon-knobs.stories.storyshot index 13bf0ff02a6..e851776c1de 100644 --- a/examples/vue-kitchen-sink/src/stories/__snapshots__/addon-knobs.stories.storyshot +++ b/examples/vue-kitchen-sink/src/stories/__snapshots__/addon-knobs.stories.storyshot @@ -40,7 +40,7 @@ exports[`Storyshots Addon|Knobs All knobs 1`] = ` exports[`Storyshots Addon|Knobs Simple 1`] = `
- I am John Doe and I'm 44 years old. + I am John Doe and I'm 40 years old.
`; diff --git a/examples/vue-kitchen-sink/src/stories/addon-knobs.stories.js b/examples/vue-kitchen-sink/src/stories/addon-knobs.stories.js index cf8a0a7d74e..60f64526596 100644 --- a/examples/vue-kitchen-sink/src/stories/addon-knobs.stories.js +++ b/examples/vue-kitchen-sink/src/stories/addon-knobs.stories.js @@ -12,17 +12,31 @@ import { button, } from '@storybook/addon-knobs'; +const logger = console; + storiesOf('Addon|Knobs', module) .addDecorator(withKnobs) - .add('Simple', () => { - const name = text('Name', 'John Doe'); - const age = number('Age', 44); - const content = `I am ${name} and I'm ${age} years old.`; + .add('Simple', () => ({ + props: { + name: { + type: String, + default: text('Name', 'John Doe'), + }, + }, - return { - template: `
${content}
`, - }; - }) + template: `
I am {{ name }} and I'm {{ age }} years old.
`, + + data() { + return { age: 40 }; + }, + + created() { + logger.log('created'); + }, + destroyed() { + logger.log('destroyed'); + }, + })) .add('All knobs', () => { const name = text('Name', 'Jane'); const stock = number('Stock', 20, {