storybookjs / storybook

Storybook is the industry standard workshop for building, documenting, and testing UI components in isolation
https://storybook.js.org
MIT License
84.7k stars 9.33k forks source link

The view is not re-rendered on toolbar change #13791

Closed ivayloc closed 3 years ago

ivayloc commented 3 years ago

Describe the bug I have created a new toolbar button following the steps in the documentation, the button is for localization change, the problem is that the story won't re-render on globals change.

Expected behavior I expect the page reloads as language is changed as it is in your official storybook

I am using @ngx-translate/core for managing the translations.

export const globalTypes = {
  locale: {
    name: 'Locale',
    description: 'Internationalization locale',
    defaultValue: 'en',
    toolbar: {
      icon: 'globe',
      items: [
        { value: 'en', right: 'en', title: 'English' },
        { value: 'he', right: 'he', title: 'Hebrew' },
      ],
    },
  },
};
const withLocaleProvider = (storyFunc, { globals: { locale } }) => {
  const story = storyFunc();

  story.moduleMetadata.imports.push(
    TranslateModule.forRoot({
      defaultLanguage: locale,
      useDefaultLang: true,
      loader: {
        provide: TranslateLoader,
        useFactory: HttpLoaderFactory,
        deps: [HttpClient],
      },
    })
  );
  return story;
}

export const decorators = [
  withLocaleProvider,
];

System

  System:
    OS: Windows 10 10.0.19041
    CPU: (8) x64 Intel(R) Core(TM) i5-8265U CPU @ 1.60GHz 
  Binaries:
    Node: 12.18.3 - C:\Program Files\nodejs\node.EXE      
    npm: 6.14.6 - C:\Program Files\nodejs\npm.CMD
  Browsers:
    Chrome: 87.0.4280.141
    Edge: Spartan (44.19041.423.0), Chromium (88.0.705.56)
  npmPackages:
    @storybook/addon-actions: ^6.1.15 => 6.1.15 
    @storybook/addon-essentials: ^6.1.15 => 6.1.15        
    @storybook/addon-links: ^6.1.15 => 6.1.15 
    @storybook/angular: ^6.1.15 => 6.1.15 
ThibaudAV commented 3 years ago

It is because of this forceRender which precisely allows not to reload the component if only args change

but then it causes this kind of problem. I don't really know how to overcome this without specific configuration 🤷‍♂️

an untested idea: You can directly call the forceReRender() function inside decorator. (import { forceReRender } from '@storybook/angular';) but ⚠️⚠️ of infinite loop if you don't make a condition to call it only if value changes (it seems to me)

ivayloc commented 3 years ago

@ThibaudAV I tried the untested idea but nothing happened, the component didn't reload.

bodograumann commented 3 years ago

I noticed the same thing with vue. In the docs tab auto-reload works though.

gomorizsolt commented 3 years ago

Same here, the "Docs" tab re-renders the component upon modifying the "globals" but the "Canvas" tab doesn't react to it.

shilman commented 3 years ago

Yay!! I just released https://github.com/storybookjs/storybook/releases/tag/v6.3.0-alpha.7 containing PR #14226 that references this issue. Upgrade today to the @next NPM tag to try it out!

npx sb upgrade --prerelease

Closing this issue. Please re-open if you think there's still more to do.

fabis94 commented 3 years ago

The issue is still present, at least with Vue. The Vue component defined in the decorators array doesn't receive the updated globals value until a re-render happens some other way like when switching to a different story or the Docs tab.

william-will-angi commented 3 years ago

+1 Issue still in Vue latest version of Storybook 6.3.8. Solution for now is to include deprecated addon-contexts package for this functionality. Not the most ideal.

sarayourfriend commented 3 years ago

Solution for now is to include deprecated addon-contexts package for this functionality

@william-will-angi Can you elaborate on this workaround for Vue and how to implement it in the meantime until this is fixed?

william-will-angi commented 3 years ago

@sarayourfriend We were using @storybook/addon-contexts@5.3.21 with our Storybook 6.x app to provide our global values without any issues. their docs

If you're determined to make it work with addon-toolbar (which is the 6.x recommendation), I created a hacky workaround in this thread which manipulates the storybook canvas to force it to work.

sarayourfriend commented 3 years ago

I saw that. I was actually able to get it working using a Vue.observable and a watch in setup:

https://github.com/WordPress/openverse-frontend/pull/346/files#diff-8371d29d475d4942ba34da809defa80e7b18f01a65da98f700b7e103980f95eeR8

Thanks for the details though!

wes0310 commented 3 years ago

I also have encountered this problem but with React Project, any workaround to solve this problem? other than including the addon-context

sarayourfriend commented 3 years ago

@wes0310 For React you should be able to follow the pattern used by WordPress/Gutenberg here: https://github.com/WordPress/gutenberg/pull/35711/files#diff-493c10b62f2ed6d7c2a9945a55b58043b0f042c6b840f78c2193f8a01b2af613R15

Basically useEffect to watch the global variable, manipulate whatever context you need to, then call forceReRender(). (forceReRender does nothing for Vue but appears to work fine for React)

wes0310 commented 3 years ago

@wes0310 For React you should be able to follow the pattern used by WordPress/Gutenberg here: https://github.com/WordPress/gutenberg/pull/35711/files#diff-493c10b62f2ed6d7c2a9945a55b58043b0f042c6b840f78c2193f8a01b2af613R15

Basically useEffect to watch the global variable, manipulate whatever context you need to, then call forceReRender(). (forceReRender does nothing for Vue but appears to work fine for React)

I tried using forceReRender(), but appears to be useless.

wes0310 commented 3 years ago

Anyone who is keeping up with this problem?

fabis94 commented 3 years ago

I moved to using useChannel() to emit the updated value of the toolbar component instead, since the toolbar controls are rendered with React: https://storybook.js.org/docs/react/addons/addons-api#usechannel

And then I've created a Vue decorator that listens for this event and re-renders the story accordingly:

import { addons } from '@storybook/addons';

(story, ctx) => ({
    template: `<template v-if="cssType"><story /></template><template v-else><whatever/></template>`,
    created() {
      this.cssTypeUpdateListener = addons
        .getChannel()
        .addListener(EVENT_CSS_TYPE_UPDATED, ({ cssType: newVal }) => {
          this.cssType = newVal;
        });
    },
    destroyed() {
      addons
        .getChannel()
        .removeListener(EVENT_CSS_TYPE_UPDATED, this.cssTypeUpdateListener);
    },
})
sarayourfriend commented 3 years ago

@wes0310 it's a closed issue, I don't know much about this repository but maybe opening a new issue tagged for React with a reproduction repo would get more attention from the devs.

william-will-angi commented 3 years ago

This issue is open: https://github.com/storybookjs/storybook/issues/12840