Mock useState in StorybookJS

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?

/components/Header/Header.stories.js

import React, { useState } from "react"; import { Header } from "./Header"; export default { title: "Components/Header", component: 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 }; 
1

3 Answers

I think you are approaching this from a wrong angle, storybook is supposed to showcase the individual components, not their parent component's logic. See Storybook Docs:

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

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

  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 component, and as such, we can use the useState hook to manage the input state!

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

 import useState from 'storybook-addon-state'; import CounterComponent from '@/components/common/htmlTags/counterCounter'; export default { title: 'Html/Counter', component: 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> ); }; 
1

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

You Might Also Like