2

I am trying to use a Template to reuse code for making some stories. Here I have a Template called Template and want to create two stories called Default and Checked.

const Template = (args) => <Checkbox {...args} />;

export const Default = Template.bind({});
export const Checked = Template.bind({});

I know that we can have decorators and parameters on each of the stories

Default.decorators = [................]
Default.parameters = {................}
Checked.decorators = [................]
Checked.parameters = {................}

But if I had decorators and parameters on the template and then use bind for my Default and Checked stories, will the decorators and parameters applied on the template work on the Default and Checked stories?????

const Template = (args) => <Checkbox {...args} />;
Template.decorators = [.............];
Template.parameters = {.............};

export const Default = Template.bind({});
export const Checked = Template.bind({});

I also want to ask, how do I use hooks with my templates? I want to be able to do something like this, but it doesn't work sadly and crashes my storybook. I want the Default and Checked stories to use the variable checker and the setIsChecked hook.

const Template = (args) => {
    const [checked, setIsChecked] = useState(true);
    return (
      <Checkbox {...args} />
    );
};

export const Default = Template.bind({});
Default.args = {
     checked: checker,
     onClick: setIsChecked,
}
export const Checked = Template.bind({});
Checked.args = {
     checked: checker,
     OnClick: setIsChecked,
}

Thank you so much!

Tony Hoan Trinh
  • 455
  • 4
  • 13

1 Answers1

0

You can use default export to export shared decorators and parameters

export default {
  title: '.../Checkbox',
  component: Checkbox,
  decorators: [
    Story => (
      <div>hi<Story/></div>
    )
  ],
  parameters: ...
} as ComponentMeta<typeof Checkbox>

And I assume that Storybook crashes with the hook with an error like "Hooks can only be called inside of the body of a function component", right? That's because the template is not a React Component, but an ordinary function. What you could do is this:

Add an actual component as a wrapper

function Controller({children}) {
  const [checked, setIsChecked] = useState(true);
  return children({checked, setIsChecked}) // using render props
}

const Template = (args) => (
  <Controller>
    {({checked, setIsChecked}) => 
      <Checkbox {...args} checked={checked} />
    }
  </Controller>
);

But the above is WRONG approach to what you want to achieve anyway. You should instead use Storybook Controls.

enter image description here

export default {
  argTypes: {
    checked: {
      type: 'boolean',
      defaultValue: true,
    },
  }
}

more reading:
https://reactjs.org/docs/render-props.html
How to pass props to {this.props.children}
https://storybook.js.org/docs/react/api/argtypes

storybook argtypes

Qwerty
  • 29,062
  • 22
  • 108
  • 136