最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Mock useState in StorybookJS - Stack Overflow

programmeradmin8浏览0评论

I wonder, what is the "Best Practice" for mocking React States in Storybooks (e.g. *.stories.js).

Currently I'm trying to implement a Dark Theme Switch.

  1. App Component has a state called "darkState", which can be set true/false
  2. App Component has a handler "handleThemeChange()", which changes MUI Theme, based upon "darkState"
  3. Header Component has a Switch or Button with "onChange()" which triggers "handleThemeChange()" in App Component
  4. The MUI Switch needs a state in order to work properly (at least I guess it does)

So, I decided to mock the state in my stories file. But writing this in a decorators seems ... strange. How do you solve this problem?

/ponents/Header/Header.stories.js

import React, { useState } from "react";
import { Header } from "./Header";

export default {
  title: "Components/Header",
  ponent: Header,
  decorators: [
    (StoryFn) => {
      // mock state
      const [darkState, setDarkState] = useState(false);
      const handleThemeChange = () => {
        setDarkState(!darkState);
        return darkState;
      };

      return (
        <Header
          enableThemeChange={true}
          handleThemeChange={handleThemeChange}
          darkState={darkState}
        />
      );
    }
  ]
};

const Template = (args) => <Header {...args} />;
export const Default = Template.bind({});

// define Controls
Default.args = {
  enableThemeChange: true,
  darkState: true
};

I wonder, what is the "Best Practice" for mocking React States in Storybooks (e.g. *.stories.js).

Currently I'm trying to implement a Dark Theme Switch.

  1. App Component has a state called "darkState", which can be set true/false
  2. App Component has a handler "handleThemeChange()", which changes MUI Theme, based upon "darkState"
  3. Header Component has a Switch or Button with "onChange()" which triggers "handleThemeChange()" in App Component
  4. The MUI Switch needs a state in order to work properly (at least I guess it does)

So, I decided to mock the state in my stories file. But writing this in a decorators seems ... strange. How do you solve this problem?

/ponents/Header/Header.stories.js

import React, { useState } from "react";
import { Header } from "./Header";

export default {
  title: "Components/Header",
  ponent: Header,
  decorators: [
    (StoryFn) => {
      // mock state
      const [darkState, setDarkState] = useState(false);
      const handleThemeChange = () => {
        setDarkState(!darkState);
        return darkState;
      };

      return (
        <Header
          enableThemeChange={true}
          handleThemeChange={handleThemeChange}
          darkState={darkState}
        />
      );
    }
  ]
};

const Template = (args) => <Header {...args} />;
export const Default = Template.bind({});

// define Controls
Default.args = {
  enableThemeChange: true,
  darkState: true
};
Share Improve this question asked Mar 5, 2021 at 16:01 DeVoltDeVolt 3411 gold badge3 silver badges18 bronze badges 1
  • storybook.js/addons/@storybook/addon-knobs ? – azium Commented Mar 5, 2021 at 16:04
Add a ment  | 

3 Answers 3

Reset to default 8

Consider approaching it from this angle instead: storybook is supposed to showcase the individual ponents, not their parent ponent's logic. See Storybook Docs:

A story captures the rendered state of a UI ponent. Developers write multiple stories per ponent that describe all the “interesting” states a ponent can support.

So instead of mocking a parent ponent and state like you've done, I remend:

  1. Create multiple stories to capture the different states (dark vs light)
  2. use the Actions addon for the handler functions, so you still receive feedback when the function is invoked.

Decorator does seem strange when used like this.

If you take a closer look, the template is itself a React functional ponent, and as such, we can use the useState hook to manage the input state!

https://javascript.plainenglish.io/a-guide-to-documenting-controlled-ponents-with-storybook-10b889c03f87

i follow this from official docs of storybook it works for me

    import useState from 'storybook-addon-state';
    import CounterComponent from '@/ponents/mon/htmlTags/counterCounter';
    
        export default {
          title: 'Html/Counter',
          ponent: CounterComponent,
          args: {
            children: 'Counter',
          },
        };
        
        export const NumberCounter = () => {
          const [numberOfCount, SetNumberOfCount] = useState('clicks', 1);
          return (
            <CounterComponent className="booking-item-group d-flex">
              <li className={`item ${numberOfCount === 1 && `active`}`}>
                <AnchorComponent
                  onClick={() => {
                    SetNumberOfCount(1);
                  }}
                  className="link"
                >
                  1
                </AnchorComponent>
              </li>
              <li className={`item ${numberOfCount === 2 && `active`}`}>
                <AnchorComponent
                  onClick={() => {
                    SetNumberOfCount(2);
                  }}
                  className="link"
                >
                  2
                </AnchorComponent>
              </li>
              <li className={`item ${numberOfCount === 3 && `active`}`}>
                <AnchorComponent
                  onClick={() => {
                    SetNumberOfCount(3);
                  }}
                  className="link"
                >
                  3
                </AnchorComponent>
              </li>
              <li className={`item ${numberOfCount === 4 && `active`}`}>
                <AnchorComponent
                  onClick={() => {
                    SetNumberOfCount(4);
                  }}
                  className="link"
                >
                  4
                </AnchorComponent>
              </li>
              <li className={`item ${numberOfCount === 5 && `active`}`}>
                <AnchorComponent
                  onClick={() => {
                    SetNumberOfCount(5);
                  }}
                  className="link"
                >
                  5
                </AnchorComponent>
              </li>
            </CounterComponent>
          );
        };
发布评论

评论列表(0)

  1. 暂无评论