Storybook: addon-docs MDX: State management

Created on 22 Jan 2020  路  11Comments  路  Source: storybookjs/storybook

I may have overlooked this since the docs are still being worked on for MDX, but what's the way to manage state in my stories using MDX? Right, now, I'm importing a component that handles the state management in a normal .js file, but then the code examples are a bit lackluster in the <Preview /> window:

<Preview>
  <Story name="Default">
    <Default />
  </Story>
</Preview>
docs inactive mdx question / support

Most helpful comment

All 11 comments

@shilman Ah, thank you very much - super useful! Have a great day!

@shilman I noticed a few funny things when attempting to get this to work, and wasn't sure if it may merit another issue being opened for each.

Spacing between code lines isn't allowed:

<Preview>
  <Story name="Default">
    {() => {
      const [value, setValue] = useState(2)

      return (
        <Range
          label="Range"
          name="example"
          value={value}
          step={1}
          min={1}
          max={20}
          disabled={boolean('Disabled', false)}
          onChange={({ target: { value: rangeValue } }) => {
            action('Current value')(rangeValue)

            setValue(rangeValue)
          }}
        />
      )
    }}
  </Story>
</Preview>

Notice the blank lines after the state declaration and in the onChange handler. With them there, I get the following:

Module build failed (from ./node_modules/@mdx-js/loader/index.js):
SyntaxError: unknown: Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>? (34:9)

  32 |   )
  33 | }}
> 34 | `}</code></pre>
     |          ^
  35 |   </Story>
  36 | </Preview>

When I remove those blank-lines, all is well.

Emotion css prop is busted

This works inside of normal CSF, but in MDX; I get the following:

You have tried to stringify object returned from `css` function. It isn't supposed to be used directly (e.g. as value of the `className` prop), but rather handed to emotion so it can handle it (e.g. as value of `css` prop).

I tried the workaround mentioned in https://github.com/storybookjs/storybook/issues/6853#issuecomment-497996054 which unfortunately didn't work, so at first-thought it'd seem like a deficiency in MDX.

I'll re-open this ticket, but definitely understand if this should be broken out; just let me know. Thanks!

thanks @zslabs! both have issues: #7902 #7540

You can use hooks in MDX stories:

https://github.com/storybookjs/storybook/blob/master/examples/official-storybook/stories/demo/button.stories.mdx#L30

Somehow I come across a problem in this way, the setCount or whatever React.SetStateAction will trigger a whole new render.
which become an issue to some complex components depend on lifecycle methods.
Sample:

{() => {
      const [count, setCount] = useState("1");
      const Wrap = styled.div`
        height: 200px;
        width: 100%;
        background-color: #eee;
        padding: 15px;
        box-sizing: border-box;
      `;
      return (
        <Wrap>
          <MyTabs defaultActiveKey={count} onChange={setCount} />
        </Wrap>
      );
    }}

when I trigger onChange, the MyTabs component will destroy & re-contruct all again.

when I try to implement it on codesandbox , Eslint yields "React Hook "useState" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function. (react-hooks/rules-of-hooks)eslint"
codesandbox, but it works, not triggering a whole new construct.

In other words: seems setCount or other SetStateAction triggers the <Story>{() => {}}</Story> execute again

Does using a function as a child only work directly under a <Story/> component? I'm trying to achieve the same thing but i only need a <Preview/> (i'm using mdx purely for docs)

@sami616 yeah i think there's some special magic for that in the Story block

Thanks for the reply, worth adding a feature request? i cant imagine i'm the only person that would benefit from this.

For anyone who comes across this, you can write a little utility component which handles this:

type FunctionProps = {
  children: () => React.ReactNode
}

export const Function = ({ children }: FunctionProps) => children()

Hi everyone! Seems like there hasn't been much going on in this issue lately. If there are still questions, comments, or bugs, please feel free to continue the discussion. Unfortunately, we don't have time to get to every issue. We are always open to contributions so please send us a pull request if you would like to help. Inactive issues will be closed after 30 days. Thanks!

Hey there, it's me again! I am going close this issue to help our maintainers focus on the current development roadmap instead. If the issue mentioned is still a concern, please open a new ticket and mention this old one. Cheers and thanks for using Storybook!

Was this page helpful?
0 / 5 - 0 ratings