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

Controls Addon - Web Components - Update property without re-rendering story #15488

Open
kgibb opened this issue Jul 5, 2021 · 13 comments
Open

Comments

@kgibb
Copy link

kgibb commented Jul 5, 2021

The Knobs addon has a disableForceUpdate option which stops the story re-rendering after a knob value has changed. There is also an event emitted when the knobs change, storybookjs/knobs/change.

The Controls addon allows the getting and setting of the control state but I don't think there's a hook point for when the value changes, like described in #9447.

Is such a pattern possible with Controls?

@shilman
Copy link
Member

shilman commented Jul 5, 2021

As far as I know there's no disableForceUpdate equivalent for args/controls. I know @tmeasday has looked at the re-rendering behavior in args/controls more than anybody and perhaps he can comment on that feature as described in #9447.

As for a controls event, the closest thing is the UPDATE_STORY_ARGS/STORY_ARGS_UPDATED events defined here: https://github.com/storybookjs/storybook/blob/next/lib/core-events/src/index.ts#L23

@shilman shilman added the PN label Jul 5, 2021
@tmeasday
Copy link
Member

tmeasday commented Jul 7, 2021

I'm not sure what use-case this is trying to solve, but if the issue is the one described in #9128 then I suspect the issue is resolved in 6.3 and this workaround isn't needed any more.

@rtrap95
Copy link

rtrap95 commented Jul 8, 2021

About this issue, I am using version 6.3.3 but components are always reloaded when changing args, so we are unable to test transition. I am missing something? Or is just solved for knobs addon and for control addon the behaviour is always rerender?

@tmeasday
Copy link
Member

@rtrap95 - can you provide a bit more detail -- are you using web components?

Components should not be remounted when changing args. If they do it is a bug.

@rtrap-rsi
Copy link

Hi @tmeasday, thanks for your reply, I am using Vue. I opened another issue with an example repo

@kgibb
Copy link
Author

kgibb commented Jul 14, 2021

I'm not sure what use-case this is trying to solve...

When a component property changes, the component might have different logic depending if it is mounted or not. Currently we can only test the unmounted branch.

... but if the issue is the one described in #9128 then I suspect the issue is resolved in 6.3 and this workaround isn't needed any more.

I am using 6.2 due to lit-html version conflicts but I tested the sample web components app with 6.3 and the below template function is invoked when the control value changes. I can also see the <button> element 'highlight' in dev tools, indicating a new element.

const Template = (args) => Button(args);

@tmeasday
Copy link
Member

@kgibb

When a component property changes, the component might have different logic depending if it is mounted or not. Currently we can only test the unmounted branch.

The correct behaviour for args is that when args change, the component should not remount. This the way knobs (was supposed to) work, too.

If that's not the case, then I suspect the issue here is a bug in the web components framework addon.

So I am still unsure about what #9447 is for exactly.

@sebakocz
Copy link

Any updates on this? I'm also experiencing an issue with seeing transition animations since the component just re-renders after changing args

@tmeasday
Copy link
Member

I think this is an open issue that someone might be able to fix in the renderToCanvas function of the html renderer:

export function renderToCanvas(

@shilman shilman removed the PN label Apr 24, 2023
@johnemau
Copy link

Disclaimer: I have only spent 5 minutes looking into this, so the following might be incorrect.

I think this is an open issue that someone might be able to fix in the renderToCanvas function of the html renderer:

export function renderToCanvas(

Looking at this history of the file it looks like renderToCanvas has always remounted the component.

It looks to me that the problem is onUpdateArgs calls rerender() on the story, when we don't want that when testing animations/transitions.

The catch is if someone doesn't have a "reactive" web component, they would probably want the current behavior to rerender the canvas to reflect the new arg.

The new forceInitialArgs property might be a potential solution here (enable it per-story) to change the remount behavior, however it currently only available for Documents.

@johnemau
Copy link

johnemau commented Apr 25, 2024

I have a workaround.

In my case the problem described above is due to how I setup my components story to rely on the default render.

For example:

// my-component.stories.js

import './my-component.js';

export default {
    component: 'my-component'
}

export const MyStory = {
   args: {
       foo: 'bar'
   }
}

The above code will always remount my-component using the "default" renderer for web components in Storybook.

The workaround

I don't see the problem if I define my own custom render function.

For example:

// my-component.stories.js

import { html } from 'lit';
import './my-component.js';

export default {
    component: 'my-component',
    render: args => html`<my-component foo=${args.foo}></my-component>`
}

export const MyStory = {
   args: {
       foo: 'bar'
   }
}

I use spreadProps to make this easier.

// my-component.stories.js

import { html } from 'lit';
import { spreadProps } from '@open-wc/lit-helpers';
import './my-component.js';

export default {
    component: 'my-component',
    render: args => html`<my-component ${spreadProps(args)}></my-component>`
}

export const MyStory = {
   args: {
       foo: 'bar'
   }
}

@TomDeSmet
Copy link

TomDeSmet commented May 24, 2024

I'm using Vue 3 and this solution works for Vue Transitions (with a Vue render function of course), but it only works if I have the default export as in your example. Problem is, Storybook's Meta needs to be the default export if I want to use that. And I can't find another way to set Meta data without it being the default export.

edit
It also seems to work with an export default Meta and a named export for my story if I wrap my component in an extra div. But I need to do that inside my actual component, using a decorator or a render function that wraps it in a div doesn't seem to work!

@johnemau
Copy link

johnemau commented Jun 1, 2024

and I can't find another way to set Meta data without it being the default export.

I am not clear on the issue you are hitting, but let me provide another example of the workaround that doesn't change the export default of the module.

import { html } from 'lit';
import { spreadProps } from '@open-wc/lit-helpers';
import './my-component.js';

export default {
    component: 'my-component',
}

export const MyStory = {
   args: {
       foo: 'bar'
   }
   render: args => html`<my-component ${spreadProps(args)}></my-component>`
}

The only thing I changed was to move the render function from the default export to the MyStory export.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants