Storybook: рд╕реАрдзреЗ рдПрдХ рдХрд╣рд╛рдиреА рдХреЗ рдЕрдВрджрд░ рд░рд┐рдПрдХреНрдЯ рд╣реБрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ

рдХреЛ рдирд┐рд░реНрдорд┐рдд 22 рдлрд╝рд░ре░ 2019  ┬╖  53рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: storybookjs/storybook

рдмрдЧ рдХрд╛ рд╡рд░реНрдгрди рдХрд░реЗрдВ

рдПрдХ рдХрд╣рд╛рдиреА рдореЗрдВ рд╕реАрдзреЗ рд╣реБрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, Hooks can only be called inside the body of a function component рд╕рд╛рде рд╡рд┐рдлрд▓ рд╣реЛрддрд╛ рд╣реИред

рдкреНрд░рдЬрдирди рдХрд░рдирд╛

рдЙрджрд╛рд╣рд░рдг рдХреЛрдб:

import React from 'react'

import { storiesOf } from '@storybook/react'

const stories = storiesOf('Hooks test', module)

const TestComponent: React.FC = () => {
  const [state, setState] = React.useState(5)
  return (
    <button onClick={() => setState(state + 1)}>
      {state}
    </button>
  )
}

stories.add('this story works', () => <TestComponent />)

stories.add('this story fails', () => {
  const [state, setState] = React.useState(5)
  return (
    <button onClick={() => setState(state + 1)}>
      {state}
    </button>
  )
})

рдЕрдкреЗрдХреНрд╖рд┐рддреН рд╡реНрдпрд╡рд╣рд╛рд░
рдкрд╣рд▓реА рдХрд╣рд╛рдиреА рдареАрдХ рдХрд╛рдо рдХрд░рддреА рд╣реИ, рджреВрд╕рд░реА рдХрд╣рд╛рдиреА рдкреНрд░рд╛рд░рдВрднрд┐рдХ рд░реЗрдВрдбрд░ рдкрд░ рд╡рд┐рдлрд▓ рд╣реЛрддреА рд╣реИ

рд╕рдВрд╕реНрдХрд░рдгреЛрдВ
@storybook/[email protected]
[email protected]
[email protected]

react has workaround question / support

рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА

рд╣рдордиреЗ рдПрдХ рд╣реА рд╕рдорд╕реНрдпрд╛ рдХрд╛ рдЕрдиреБрднрд╡ рдХрд┐рдпрд╛ рд╣реИ, рдФрд░ рдпрд╣ рдПрдХ рд╕рд░рд▓ рд╣реИрдХ рд╣реИ рдЬрд┐рд╕реЗ рд╣рдо рдЗрд╕реЗ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд░рддреЗ рд╣реИрдВред

stories.add('this story fails', () => React.createElement(() => {
  const [state, setState] = React.useState(5)
  return (
    <button onClick={() => setState(state + 1)}>
      {state}
    </button>
  )
}))

рдореИрдВ рдорд╛рдирддрд╛ рд╣реВрдВ рдХрд┐ рдпрд╣ рдмрд┐рдирд╛ рд╣реИрдХ рдХреЗ рдореВрд▓ рд░реВрдк рд╕реЗ рд╕рдорд░реНрдерд┐рдд рд╣реЛрдирд╛ рдмреЗрд╣рддрд░ рд╣реЛрдЧрд╛ред рдпрджрд┐ рдЕрдиреБрдЪрд░ рднреА рд╕рд╣рдордд рд╣реИрдВ, рддреЛ рд╢рд╛рдпрдж рдореБрдЭреЗ рдкреАрдЖрд░ PR рдХреЗ рд╕рд╛рде рдЖрдиреЗ рдХреЗ рд▓рд┐рдП рдХреБрдЫ рд╕рдордп рдорд┐рд▓ рд╕рдХрддрд╛ рд╣реИред

рд╕рднреА 53 рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

рдпрдХреАрди рдирд╣реАрдВ рд╣реЛрддрд╛ рдХрд┐ рдпрд╣ рдПрдХ рдмрдЧ рд╣реИред рдореЗрд░рд╛ рдорд╛рдирдирд╛ тАЛтАЛрд╣реИ, рдФрд░ рдореИрдВ рдЧрд▓рдд рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, stories.add рдХрд╛ рджреВрд╕рд░рд╛ рддрд░реНрдХ рдПрдХ рдШрдЯрдХ рдХреЛ рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдХреА рдЙрдореНрдореАрдж рдХрд░ рд░рд╣рд╛ рд╣реИ рди рдХрд┐ рдПрдХ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд░рд┐рдПрдХреНрдЯ рдШрдЯрдХред рдЕрдкрдиреЗ рдлрдВрдХреНрд╢рди рдХрдВрдкреЛрдиреЗрдВрдЯ рдХреЛ рдмрд╛рд╣рд░ рддрдХ рд▓реЗ рдЬрд╛рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реЗрдВ, рдЖрдкрдХреЛ рдХреБрдЫ рд╕рдлрд▓рддрд╛ рдорд┐рд▓рдиреА рдЪрд╛рд╣рд┐рдПред

рдЙрджрд╛рд╣рд░рдг

function SomeComponent() {
    const [blah] = React.useState('blah');
    return <div> {blah}</div>;
}
stories.add('BlahComponent', () => <SomeComponent />);

рдореЗрд░рд╛ рдорд╛рдирдирд╛ тАЛтАЛрд╣реИ, рдФрд░ рдореИрдВ рдЧрд▓рдд рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, stories.add рдХрд╛ рджреВрд╕рд░рд╛ рддрд░реНрдХ рдПрдХ рдШрдЯрдХ рдХреЛ рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдХреА рдЙрдореНрдореАрдж рдХрд░ рд░рд╣рд╛ рд╣реИ рди рдХрд┐ рдПрдХ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд░рд┐рдПрдХреНрдЯ рдШрдЯрдХред

рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ AFAIK рд╕реЗ рдХреЛрдИ рдлрд░реНрдХ рдирд╣реАрдВ рдкрдбрд╝рддрд╛, рд▓реЗрдХрд┐рди рдпрд╣ рд╣рдореЗрд╢рд╛ рдХреЛрд╢рд┐рд╢ рдХрд░рдиреЗ рд▓рд╛рдпрдХ рд╣реИред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, @ рдЕрднрд┐рдорд╛рдиреА рдХреНрдпрд╛ рддреНрд░реБрдЯрд┐ рдлреЗрдВрдХрддрд╛ рд╣реИ? рд╕реНрдЯреЛрд░реАрдмреБрдХ рдпрд╛ рдЯрд╛рдЗрдк рд╕рд┐рд╕реНрдЯрдо?

@Keraito рдирд╣реАрдВ, рдореБрдЭреЗ рдкреВрд░рд╛ рдпрдХреАрди рд╣реИ рдХрд┐ рддреНрд░реБрдЯрд┐ рд╕рд╣реА рд╣реИред

рдРрд╕рд╛ рдЗрд╕рд▓рд┐рдП рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рд╣рдо рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЗ рд╕рдВрджрд░реНрдн рд╕реЗ рдмрд╛рд╣рд░ рдмреБрд▓рд╛ рд░рд╣реЗ рд╣реИрдВ, рдЙрд░реНрдл тАЛтАЛрд╕реНрдЯреЛрд░реАрдмреБрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдЗрд╕ рддрд░рд╣ рдмреБрд▓рд╛рдПрдЧрд╛:

const element = storyFn();

рдирд╣реАрдВ

const element = <StoryFn />

рдХрд╛рдлреА рд╕рдВрднрд╡рдд: рдЕрдЧрд░ рд╣рдо рдЗрд╕реЗ рдЗрд╕ рддрд░рд╣ рд╢реБрд░реВ рдХрд░реЗрдВрдЧреЗ рдХрд┐ рдпрд╣ рдХрд╛рдо рдХрд░ рд╕рдХреЗред

рдЕрднреА @gabefromutah рдХреА рд╕рд▓рд╛рд╣ рдзреНрд╡рдирд┐ рд╣реИред

рдпрд╣рд╛рдБ рдХреЛрдб рдХреА рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд▓рд╛рдЗрди рд╣реИ:
https://github.com/storybooks/storybook/blob/next/app/react/src/client/preview/render.js#L24

рдпрджрд┐ рдХреЛрдИ рдЗрд╕ рдХрд╛рдо рдХреЛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреНрд░рдпреЛрдЧ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реИ, рддреЛ рдпрд╣ рд╢реБрд░реВ рдХрд░рдиреЗ рдХреА рдЬрдЧрд╣ рд╣реИ, рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИред

@sargant рдХреНрдпрд╛ рдЖрдкрдХреЗ рд▓рд┐рдП @gabefromutah рдХрд╛ рд╕реБрдЭрд╛рд╡ рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИ?

@ndelangen @gabefromutah рдХрд╛ рд╕реБрдЭрд╛рд╡ рдореЗрд░реА рдкреНрд░рд╛рд░рдВрднрд┐рдХ "рдЗрд╕ рдХрд╣рд╛рдиреА рдкрд░ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ" рдЙрджрд╛рд╣рд░рдг рдХреЗ рд╕рдорд╛рди рд╣реИ рдЬреЛ рдореБрдЭреЗ рд╡рд┐рд╢реНрд╡рд╛рд╕ рд╣реИ?

рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ рдХрд┐ рдпрд╣ рдмрдЧ рдирд╣реАрдВ рд╣реИ, рдлрд┐рд░ рднреА рд░рд╛рдЬреНрдп рдХреЗ рд▓рд┐рдП рддреГрддреАрдп-рдкрдХреНрд╖ рдкреНрд▓рдЧрдЗрдиреНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рд╕реЗ рдмрдЪрдиреЗ рдХреЗ рд▓рд┐рдП рдпрд╣ рдПрдХ рдЙрдкрдпреЛрдЧреА рд╡реГрджреНрдзрд┐ рд╣реЛ рд╕рдХрддреА рд╣реИред

рдХрд╛рдлреА рд╕рдВрднрд╡рдд: рдЕрдЧрд░ рд╣рдо рдЗрд╕реЗ рдЗрд╕ рддрд░рд╣ рд╢реБрд░реВ рдХрд░реЗрдВрдЧреЗ рдХрд┐ рдпрд╣ рдХрд╛рдо рдХрд░ рд╕рдХреЗред

@ndelangen рдХреЛ рдЗрд╕ рдмрд╛рдд рдкрд░ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдпрдХреАрди рдирд╣реАрдВ рд╣реИ рдХрд┐ рдпрд╣ рдЕрдиреНрдп рдирд┐рд╢реНрдЪрд┐рдд addon-info , рдЬрд┐рд╕реЗ рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд рд░реЗрдВрдбрд░ рдШрдЯрдХ рдХреЗ рдкреНрд░реЙрдкреНрд╕ рдЬреИрд╕реА рдЬрд╛рдирдХрд╛рд░реА рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред

рд╣рдордиреЗ рдПрдХ рд╣реА рд╕рдорд╕реНрдпрд╛ рдХрд╛ рдЕрдиреБрднрд╡ рдХрд┐рдпрд╛ рд╣реИ, рдФрд░ рдпрд╣ рдПрдХ рд╕рд░рд▓ рд╣реИрдХ рд╣реИ рдЬрд┐рд╕реЗ рд╣рдо рдЗрд╕реЗ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд░рддреЗ рд╣реИрдВред

stories.add('this story fails', () => React.createElement(() => {
  const [state, setState] = React.useState(5)
  return (
    <button onClick={() => setState(state + 1)}>
      {state}
    </button>
  )
}))

рдореИрдВ рдорд╛рдирддрд╛ рд╣реВрдВ рдХрд┐ рдпрд╣ рдмрд┐рдирд╛ рд╣реИрдХ рдХреЗ рдореВрд▓ рд░реВрдк рд╕реЗ рд╕рдорд░реНрдерд┐рдд рд╣реЛрдирд╛ рдмреЗрд╣рддрд░ рд╣реЛрдЧрд╛ред рдпрджрд┐ рдЕрдиреБрдЪрд░ рднреА рд╕рд╣рдордд рд╣реИрдВ, рддреЛ рд╢рд╛рдпрдж рдореБрдЭреЗ рдкреАрдЖрд░ PR рдХреЗ рд╕рд╛рде рдЖрдиреЗ рдХреЗ рд▓рд┐рдП рдХреБрдЫ рд╕рдордп рдорд┐рд▓ рд╕рдХрддрд╛ рд╣реИред

@ kevin940726 рдЬреЛ рднрдпрд╛рдирдХ 7 рд╣реЛрдЧрд╛

рдореЗрд░реЗ .storybook / config.js рдХреЗ рд▓рд┐рдП рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЬреЛрдбрд╝рдирд╛ рдореЗрд░реЗ рд▓рд┐рдП рдХрд╛рдо рдХрд┐рдпрд╛

addDecorator((Story) => <Story />)

рдореИрдВрдиреЗ рдХреБрдЫ рдЗрд╕реА рддрд░рд╣ рд╕реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдРрдбрдСрди рдХрд╛ рдПрдХ рдЧреБрдЪреНрдЫрд╛ рдЯреВрдЯ рдЬрд╛рддрд╛ рд╣реИ, рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдПрдб-рдкреНрд░реЙрдк рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реАрдХрд░рдг рдХреЗ рд▓рд┐рдП рдПрдбрдСрди-рдЬрд╛рдирдХрд╛рд░реАред рдореИрдВрдиреЗ рддрдп рдХрд┐рдпрд╛ рд╣реИ рдХрд┐ рд╣реБрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЙрд╕ рдЬрд╛рдирдХрд╛рд░реА рд╕реЗ рдЕрдзрд┐рдХ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ (рдЬреИрд╕рд╛ рдХрд┐ рдореИрдВ рдЕрд▓рдЧ-рдЕрд▓рдЧ рд╡реИрд╕реЗ рднреА рдЙрддреНрдкрдиреНрди рдХрд░рддрд╛ рд╣реВрдВ), рд▓реЗрдХрд┐рди рдореБрдЭреЗ рд╕рдВрджреЗрд╣ рд╣реИ рдХрд┐ рд╕рд╛рдорд╛рдиреНрдп рд░реВрдк рд╕реЗ рд╕реНрдЯреЛрд░реАрдмреБрдХ рдХреЗ рд╕рднреА рдкрд░ рд▓рд╛рдЧреВ рд╣реЛрдЧрд╛ред рдкрддрд╛ рдирд╣реАрдВ рдХреИрд╕реЗ рдЖрдк рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЗ рдмрд╛рд╣рд░ рдПрдкреАрдЖрдИ рдХреА рддрд░рд╣ рдПрдХ рд╣реБрдХ рд╕рдВрднрд╛рд▓ рд▓реЗрдВрдЧреЗред

рдореИрдВрдиреЗ рдЗрд╕реЗ рд╕реНрд░реЛрдд рдХреЛрдб рдореЗрдВ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХреА, рд▓реЗрдХрд┐рди рдореБрдЭреЗ рдЗрд╕реЗ рд╕реНрдЯреЛрд░реА-рдПрдб-рдПрдбреЛрди рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрдард┐рди рд╕рдордп рдорд┐рд▓ рд░рд╣рд╛ рд╣реИред рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдПрдХ рдмреНрд░реЗрдХрд┐рдВрдЧ рдкрд░рд┐рд╡рд░реНрддрди рд╣реЛрдЧрд╛ рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рд╣рд░ рд╕реНрдиреИрдкрд╢реЙрдЯ рдореЗрдВ рдПрдХ рдирдпрд╛ рдореВрд▓ рдиреЛрдб рдЙрддреНрдкрдиреНрди рдХрд░реЗрдЧрд╛ред рдЬреИрд╕рд╛ рдХрд┐ рд╣рдо рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдЪреБрдирдиреЗ рд╡рд╛рд▓реЗ рд░реЗрдВрдбрд░рд░ рдХреЗ рдирд┐рдпрдВрддреНрд░рдг рдореЗрдВ рдирд╣реАрдВ рд╣реЛрддреЗ рд╣реИрдВ, рд╣рдо рдПрдХ рд╕реНрддрд░ рддрдХ рдЧрд╣рд░реЗ рдореЗрдВ рдЧреЛрддрд╛ рдирд╣реАрдВ рд▓рдЧрд╛ рд╕рдХрддреЗ рд╣реИрдВред рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рд╣рдореЗрдВ рдЕрдиреНрдп рд╡рд┐рдХрд▓реНрдкреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕реЛрдЪрдирд╛ рдкрдбрд╝ рд╕рдХрддрд╛ рд╣реИ, рдЬреИрд╕реЗ рд╣рдо рд╕рдорд╛рдзрд╛рди рдХрд╛ рджрд╕реНрддрд╛рд╡реЗрдЬреАрдХрд░рдг рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЛ рдСрдкреНрдЯ-рдЗрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреБрдЫ рд╕рд╣рд╛рдпрдХ рдПрдкреАрдЖрдИ рдкреНрд░рджрд╛рди рдХрд░реЗрдВред

рдореЗрд░реЗ .storybook / config.js рдХреЗ рд▓рд┐рдП рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЬреЛрдбрд╝рдирд╛ рдореЗрд░реЗ рд▓рд┐рдП рдХрд╛рдо рдХрд┐рдпрд╛

addDecorator((Story) => <Story />)

@emjaksa рдХреНрдпрд╛ рдЖрдк рдЗрд╕ рдХрд╛ рдПрдХ рдЯреБрдХрдбрд╝рд╛ рдкреНрд░рджрд╛рди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ?

рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЗ рд▓рд┐рдП рдпрд╣ рдореЗрд░рд╛ рдХрд╛рдо рдерд╛:

import React, { useState } from 'react';

import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions';
import { withInfo } from '@storybook/addon-info';

import SelectField from 'component-folder/SelectField';

/**
 * special wrapper that replaces the `value` and `onChange` properties to make
 * the component work hooks
 */
const SelectFieldWrapper = props => {
  const [selectValue, setValue] = useState('');

  return (
    <SelectField
      {...props}
      value={selectValue}
      onChange={e => {
        setValue(e.target.value);
        action('onChange')(e.target.value);
      }}
    />
  );
};
SelectFieldWrapper.displayName = 'SelectField';

const info = {
  text: SelectField.__docgenInfo.description,
  propTables: [SelectField],
  propTablesExclude: [SelectFieldWrapper]
};

storiesOf('Controls/SelectField', module)
  .addDecorator(withInfo)

  // ... some stories

  // this example uses a wrapper component to handle the `value` and `onChange` props, but it should
  // be interpreted as a <SelectField> component
  .add('change handler', () => 
    <SelectFieldWrapper
      id="employment-status"
      placeholder="some placeholder"
      value={//selectValue}
      onChange={e => {
          // setValue(e.target.value);
      }}
    />, { info });

рдЬреИрд╕рд╛ рдХрд┐ рдореИрдВрдиреЗ рдмрддрд╛рдпрд╛ рдХрд┐ рдЕрднреА рднреА рдПрдХ рд╡рд░реНрдХрдЕрд░рд╛рдЙрдВрдб рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдФрд░ info рдПрдбрдСрди рдХреЛ рддреЛрдбрд╝рддрд╛ рдирд╣реАрдВ рд╣реИред (рдореИрдВрдиреЗ рдЕрдиреНрдп рд╡реНрдпрд╕рдиреЛрдВ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдирд╣реАрдВ рдХрд┐рдпрд╛ рд╣реИ)

рдореЗрд░реА рдЬрд╛рдирдХрд╛рд░реА addon рдирд╣реАрдВ рддреЛрдбрд╝рддреА рд╣реИ рдмрд╢рд░реНрддреЗ рдореИрдВрдиреЗ рд╕реНрдЯреЛрд░реА рдбреЗрдХреЛрд░реЗрдЯрд░ рдХреЛ рдЕрдВрддрд┐рдо рд░реВрдк рд╕реЗ рдЬреЛрдбрд╝рд╛ред

import React from 'react'

import { configure, addDecorator } from '@storybook/react'
import { withInfo } from '@storybook/addon-info'
import { withKnobs } from '@storybook/addon-knobs'

const req = require.context('../src', true, /\.stories\.js$/)

function loadStories() {
  req.keys().forEach(filename => req(filename))
}

addDecorator(
  withInfo({
    header: false,
  }),
)
addDecorator(withKnobs)
addDecorator((Story) => (
    <Story />
))

configure(loadStories, module)

рдЕрднреА рддрдХ рдПрдХ рдФрд░ рд╕рдорд╛рдзрд╛рди:

рдореЗрд░реЗ рдкрд╛рд╕ рдПрдХ рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдШрдЯрдХ рд╣реИ рдЬрд┐рд╕реЗ UseState рдЗрд╕ рддрд░рд╣ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ:

export const UseState = ({ render, initialValue }) => {
    const [ variable, setVariable ] = useState(initialValue)
    return render(variable, setVariable)
}

рдФрд░ рдореИрдВ рдЗрд╕реЗ рдЗрд╕ рддрд░рд╣ рдХрд╣рд╛рдирд┐рдпреЛрдВ рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВ:

.add('use state example', () => (
    <UseState
        initialValue={0}
        render={(counter, setCounter) => (            
            <button onClick={() => setCounter(counter + 1)} >Clicked {counter} times</button>
        )}
    />
)

рд▓реЗрдХрд┐рди рдореБрдЭреЗ @ kevin940726 рдХрд╛

рдореИрдВ рд░рд╛рдЬреНрдп рдкрд░рд┐рд╡рд░реНрддрди рдкрд░ рдлрд┐рд░ рд╕реЗ рдкреНрд░рд╕реНрддреБрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╣рд╛рдиреА рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдореЗрдВ рдЕрд╕рдорд░реНрде рд╣реВрдВред рдлреЛрд░реНрд╕ рд░реА-рд░реЗрдВрдбрд░рд┐рдВрдЧ рднреА рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред

рдЬрдмрдХрд┐ рдпрд╣ рдХреЛрдб рд░рд┐рдПрдХреНрдЯ рд╣реБрдХ рдХреЗ рд▓рд┐рдП рдЕрдЪреНрдЫрд╛ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ

storiesOf("Dropdowns", module).add("Basic", () => <DropdownBasicStory />);

рдпрд╣ @storybook/addon-info рд╕рд╛рде рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ:
Screenshot 2019-05-13 14 35 10

рдпрд╣ рдЗрд╕ рд╕рдорд╛рдзрд╛рди рдХреЛ рдЕрдиреБрдкрдпреЛрдЧреА рдмрдирд╛рддрд╛ рд╣реИред рдХреЛрдИ рд╡рд┐рдЪрд╛рд░? рд╕реНрдЯреЛрд░реАрдмреБрдХ 5.1.0-beta.0

@artyomtrityak рдЖрдк рдУрд╡рд░рд░рд╛рдЗрдб рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ propTables рдореЗрдВ рд╡рд┐рдХрд▓реНрдк addon-info ? рдореИрдВ рдЗрд╕реЗ рдЖрдЧрд╛рдореА addon-docs рдореЗрдВ рдареАрдХ рд╕реЗ рд╣рд▓ рдХрд░реВрдВрдЧрд╛: https://medium.com/storybookjs/storybook-docs-sneak-peak-5be78445094a

@ рд╢реАрд▓рдореИрди рдореЗрдВ <DropdownBasicStory /> рдХрд╛ рд╕реНрд░реЛрдд рднреА рд╢рд╛рдорд┐рд▓ рд╣реЛрдЧрд╛?

@artyomtrityak рдореИрдВ рджреЗрдЦреВрдВрдЧрд╛ рдХрд┐ рдореИрдВ рдХреНрдпрд╛ рдХрд░ рд╕рдХрддрд╛ рд╣реВрдВ

рд╣реЗрд▓реЛ рд╕рдм рд▓реЛрдЧ! рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЗрд╕ рдореБрджреНрджреЗ рдкрд░ рд╣рд╛рд▓ рд╣реА рдореЗрдВ рдмрд╣реБрдд рдХреБрдЫ рдирд╣реАрдВ рд╣реБрдЖ рд╣реИред рдпрджрд┐ рдЕрднреА рднреА рдкреНрд░рд╢реНрди, рдЯрд┐рдкреНрдкрдгреА рдпрд╛ рдмрдЧ рд╣реИрдВ, рддреЛ рдХреГрдкрдпрд╛ рдЪрд░реНрдЪрд╛ рдЬрд╛рд░реА рд░рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рд╕реНрд╡рддрдВрддреНрд░ рдорд╣рд╕реВрд╕ рдХрд░реЗрдВред рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╣рд░ рдореБрджреНрджреЗ рдкрд░ рдЖрдиреЗ рдХрд╛ рд╕рдордп рдирд╣реАрдВ рд╣реИред рд╣рдо рд╣рдореЗрд╢рд╛ рдпреЛрдЧрджрд╛рди рдХреЗ рд▓рд┐рдП рдЦреБрд▓реЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рдХреГрдкрдпрд╛ рд╣рдореЗрдВ рдПрдХ рдкреБрд▓ рдЕрдиреБрд░реЛрдз рднреЗрдЬреЗрдВ рдЕрдЧрд░ рдЖрдк рдорджрдж рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред рдирд┐рд╖реНрдХреНрд░рд┐рдп рдореБрджреНрджреЛрдВ рдХреЛ 30 рджрд┐рдиреЛрдВ рдХреЗ рдмрд╛рдж рдмрдВрдж рдХрд░ рджрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдзрдиреНрдпрд╡рд╛рдж!

рдЕрдЧрд░ рдХрд┐рд╕реА рдФрд░ рдХреЛ рдпрд╣ рдЕрднреА рднреА рдорд┐рд▓ рд░рд╣рд╛ рд╣реИ, рддреЛ рдореИрдВрдиреЗ рдкрд╛рдпрд╛ рдХрд┐ рд╕рдорд╕реНрдпрд╛ рдПрдХ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдШрдЯрдХ рдореЗрдВ рдкреНрд░реЛрдк рдкреНрд░рдХрд╛рд░ рдЬреЛрдбрд╝ рд░рд╣реА рд╣реИред

const Dropdown = () => (
  // component content
);

Dropdown.propTypes = {
  ...
}

рдХрд┐рд╕реА рдХрд╛рд░рдг рд╕реЗ .propTypes рдЯрд┐рдкреНрдкрдгреА рдХрд░рдиреЗ рд╕реЗ рдпрд╣ рдХрд╛рдо рдХрд░рдиреЗ рд▓рдЧрддрд╛ рд╣реИред рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдирд╣реАрдВ рд╣реИ рдХрд┐ рдпрд╣ рдПрдХ рдкреНрд░рдХрд╛рд░ рдХрд╛ рдореБрджреНрджрд╛ рд╣реИ рдЬреЛ рдкреНрд░рд▓реЗрдЦрди рдХреЗ рд▓рд┐рдП рдкрд╛рд░реНрд╕рд┐рдВрдЧ рдпрд╛ рдХреБрдЫ рдФрд░ рдХреЗ рд╕рд╛рде рд╣реИред

рд╣реБрдХ рдХреЗ рд╕рд╛рде рдШрдЯрдХреЛрдВ рдХреЗ рд╕реНрд░реЛрдд рдХреЛрдб рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП

function WithState({ children }) {
  const [value, setValue] = React.useState([]);

  return React.cloneElement(children, {
    value,
    onChange: event => setValue(event.target.value),
  });
}

storiesOf(`${__dirname}`, module).add('Basic', () => (
  <WithState>
    <select value="[parent state]" onChange="[parent func]">
      <option value="Australia">Australia</option>
      <option value="Cambodia">Cambodia</option>
    </select>
  </WithState>
));

рд╣реЗрд▓реЛ рд╕рдм рд▓реЛрдЧ! рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЗрд╕ рдореБрджреНрджреЗ рдкрд░ рд╣рд╛рд▓ рд╣реА рдореЗрдВ рдмрд╣реБрдд рдХреБрдЫ рдирд╣реАрдВ рд╣реБрдЖ рд╣реИред рдпрджрд┐ рдЕрднреА рднреА рдкреНрд░рд╢реНрди, рдЯрд┐рдкреНрдкрдгреА рдпрд╛ рдмрдЧ рд╣реИрдВ, рддреЛ рдХреГрдкрдпрд╛ рдЪрд░реНрдЪрд╛ рдЬрд╛рд░реА рд░рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рд╕реНрд╡рддрдВрддреНрд░ рдорд╣рд╕реВрд╕ рдХрд░реЗрдВред рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╣рд░ рдореБрджреНрджреЗ рдкрд░ рдЖрдиреЗ рдХрд╛ рд╕рдордп рдирд╣реАрдВ рд╣реИред рд╣рдо рд╣рдореЗрд╢рд╛ рдпреЛрдЧрджрд╛рди рдХреЗ рд▓рд┐рдП рдЦреБрд▓реЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рдХреГрдкрдпрд╛ рд╣рдореЗрдВ рдПрдХ рдкреБрд▓ рдЕрдиреБрд░реЛрдз рднреЗрдЬреЗрдВ рдЕрдЧрд░ рдЖрдк рдорджрдж рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред рдирд┐рд╖реНрдХреНрд░рд┐рдп рдореБрджреНрджреЛрдВ рдХреЛ 30 рджрд┐рдиреЛрдВ рдХреЗ рдмрд╛рдж рдмрдВрдж рдХрд░ рджрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдзрдиреНрдпрд╡рд╛рдж!

рдЙрдкрд░реЛрдХреНрдд React.createElement рдФрд░ <Story /> рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЗ рд╕рд╛рде рд╕рд╛рд╡рдзрд╛рди рд░рд╣реЗрдВ, рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рд╡реЗ рдХреБрдЫ рдорд╛рдорд▓реЛрдВ рдореЗрдВ рдмрд┐рд▓реНрдХреБрд▓ рд╕рд╣реА рдирд╣реАрдВ рд╣реИрдВ, рдХреНрдпреЛрдВрдХрд┐ рдЖрдк рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдШрдЯрдХреЛрдВ (рдХрд╣рд╛рдиреА рдШрдЯрдХ) рдХреЛ рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рдХреЗ рдмрдЬрд╛рдп рдлрд┐рд░ рд╕реЗ рдмрдирд╛ рд░рд╣реЗ рд╣реИрдВ рд░реЗрдВрдбрд░ рдХрд┐рдП рдЧрдП рддрддреНрд╡ (рдбреЙрдХреНрд╕рдмреБрдХ рдореЗрдВ story() рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП рдбреЙрдХреНрд╕ рдореЗрдВ рджрд┐рдЦрд╛рдП рдЧрдП рдЕрдиреБрд╕рд╛рд░ config.js )ред

рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЬрдм рдЖрдкрдХреА рдХрд╣рд╛рдиреА рдореЗрдВ Knobs.button рдЬреЛ рдШрдЯрдХ рд╕реНрдерд╛рдиреАрдп рд╕реНрдерд┐рддрд┐ рдЕрдкрдбреЗрдЯ рдХреЛ рдЯреНрд░рд┐рдЧрд░ рдХрд░рддрд╛ рд╣реИ, рддреЛ рдмрдЯрди рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, рдЖрдк рд╡рд░реНрддрдорд╛рди рдШрдЯрдХ рдХреА рд╕реНрдерд┐рддрд┐ рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рдиреЗ рдХреЗ рдмрдЬрд╛рдп рдПрдХ рдирдпрд╛ рдХрд╣рд╛рдиреА рдШрдЯрдХ рдмрдирд╛рдиреЗ рдХреА рд╕рдВрднрд╛рд╡рдирд╛ рд░рдЦрддреЗ рд╣реИрдВред

рдЖрдк рдЗрд╕ рд╕рд░рд▓ рдХреЛрдб рд╕реНрдирд┐рдкреЗрдЯ рдХреЗ рд╕рд╛рде рдореЗрд░реА рдзрд╛рд░рдгрд╛ рдХреЛ рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЬрд╣рд╛рдВ рдиреЙрдмреНрд╕ рдмрдЯрди рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рдореВрд▓реНрдп рдХреЛ рдЕрдкрдбреЗрдЯ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред

storiesOf('Test', module).add('with text', () => {
  return React.createElement(() => {
    const [value, setValue] = React.useState(1);

    Knobs.button('Increase', () => setValue(prev => prev + 1));

    return <span>{value}</span>;
  });
});

рдпрд╣ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдк рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:

function MyStory() {
  const [value, setValue] = React.useState(1);

  Knobs.button('Increase', () => setValue(prev => prev + 1));

  return <span>{value}</span>;
}

storiesOf('Test', module).add('with text', () => <MyStory />);

рдЗрд╕рд▓рд┐рдП, рд╡рд░реНрдХрдЕрд░рд╛рдЙрдВрдб рдХреЗ рд░реВрдк рдореЗрдВ, рдореИрдВрдиреЗ рдПрдХ рдЖрд╡рд░рдг рдмрдирд╛рдпрд╛ рд╣реИ:

import {
  DecoratorParameters,
  Story,
  StoryDecorator,
  storiesOf as origStoriesOf,
} from '@storybook/react';

class ReactStory {
  private readonly story: Story;

  constructor(name: string, module: NodeModule) {
    this.story = origStoriesOf(name, module);
  }

  public add(
    storyName: string,
    Component: React.ComponentType,
    parameters?: DecoratorParameters
  ): this {
    this.story.add(storyName, () => <Component />, parameters);
    return this;
  }

  public addDecorator(decorator: StoryDecorator): this {
    this.story.addDecorator(decorator);
    return this;
  }

  public addParameters(parameters: DecoratorParameters): this {
    this.story.addParameters(parameters);
    return this;
  }
}

new ReactStory('Test', module).add('with text', () => {
  const [value, setValue] = React.useState(1);

  Knobs.button('Increase', () => setValue(prev => prev + 1));

  return <span>{value}</span>;
});

рд╡реИрдХрд▓реНрдкрд┐рдХ рд░реВрдк рд╕реЗ, рдЖрдк рд░реАрдЪрд╛рд░реНрдЬрд┐рдВрдЧ рдУрд╡рд░рд╣реЗрдб рдХреЛ рдХрдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реНрдЯреЛрд░реАрдмреБрдХ рдПрдкреАрдЖрдИ рдХреА рдирдХрд▓ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ рдмрд╛рдж рдореЗрдВ рд╕реНрд╡рд┐рдЪ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬрдм рд╕рдорд╕реНрдпрд╛ рдареАрдХ рд╣реЛ рдЧрдИ рдереАред

export function storiesOf(name: string, module: NodeModule) {
  return new ReactStory(name, module);
}

рдореИрдВ рдЧрд▓рдд рд╣реЛ рд╕рдХрддрд╛ рд╣реВрдВ, рдпрджрд┐ рд╣рд╛рдВ, рддреЛ рдХреГрдкрдпрд╛ рдореБрдЭреЗ рдмрддрд╛рдПрдВред рдмрд╣реБрдд рд╕рд░рд╛рд╣рдирд╛ рдХреА!

рдЯрд╛-рджрд╛ !! рдореИрдВрдиреЗ рдЕрднреА-рдЕрднреА https://github.com/storybookjs/storybook/releases/tag/v5.2.0-beta.10 рдкрд░ PR # 7571 рдпреБрдХреНрдд рд╡рд┐рдореЛрдЪрди рдХрд┐рдпрд╛ рдЬреЛ рдЗрд╕ рдореБрджреНрджреЗ рдХреЛ рд╕рдВрджрд░реНрднрд┐рдд рдХрд░рддрд╛ рд╣реИред рдЗрд╕реЗ рдЖрдЬрдорд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдЬ рд╣реА рдЕрдкрдЧреНрд░реЗрдб рдХрд░реЗрдВ!

рдЖрдк рдЗрд╕ @next рдПрдирдкреАрдПрдо рдЯреИрдЧ рдкрд░ рдЗрд╕ рдкреНрд░реАрд▓реЗрд░реЗрдЬ рдХреЛ рдкрд╛ рд╕рдХрддреЗ рд╣реИрдВред

рдЗрд╕ рдореБрджреНрджреЗ рдХреЛ рдмрдВрдж рдХрд░рдирд╛ред рдХреГрдкрдпрд╛ рдкреБрди: рдЦреЛрд▓реЗрдВ рдпрджрд┐ рдЖрдкрдХреЛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЕрднреА рдФрд░ рдХреБрдЫ рдХрд░рдирд╛ рдмрд╛рдХреА рд╣реИред

@ рд╢рд┐рд▓реНрдкреА рдзрдиреНрдпрд╡рд╛рдж !! рдХреНрдпрд╛ рдЖрдкрдХреЗ рдкрд╛рд╕ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдПрдХ рдХреЛрдб рд╕реНрдирд┐рдкреЗрдЯ рдЙрджрд╛рд╣рд░рдг рд╣реИ?

@shiranZe рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВ: https://github.com/storybookjs/storybook/blob/next/examples/official-storybook/stories/demo/button.stories.jpg#L26

@ рд╢рд┐рд▓реНрдкреА рдзрдиреНрдпрд╡рд╛рдж!
рд▓реЗрдХрд┐рди рдЕрднреА рднреА рддреНрд░реБрдЯрд┐ рд╣реЛ рд░рд╣реА рд╣реИ:
рд░рд┐рдПрдХреНрдЯ рд╣реВрдХ "рдпреВрдЬрд╝рд╕реНрдЯреНрд░реЗрдЯ" рдХреЛ рдлрдВрдХреНрд╢рди "рдХрдВрдкреЛрдиреЗрдВрдЯ" рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬреЛ рди рддреЛ рд░рд┐рдПрдХреНрдЯ рдлрдВрдХреНрд╢рди рдХрдВрдкреЛрдиреЗрдВрдЯ рд╣реИ рдФрд░ рди рд╣реА рдХрд╕реНрдЯрдо рд░рд┐рдПрдХреНрдЯ рд╣реБрдХ рдлрдВрдХреНрд╢рди

@ рд╢рд┐рд░рд╛рдирдЬрд╝реЗ рдЖрдк рд╣рд╛рд▓ рд╣реА рдореЗрдВ 5.2-рдмреАрдЯрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВ?

@ рд▓рдХреНрд╖реНрдордг рд╣рд╛рдВ ...

рдХрд╣рд╛рдирд┐рдпреЛрдВ / рдШрдЯрдХреЛрдВ / рдореЗрдиреВ / index.js рдкрд░ рдореЗрд░рд╛ рдХреЛрдб:

const рдШрдЯрдХ = () => {
const [buttonEl, setButtonEl] = useState (рдирд▓)

const handleClick = (event) => {
    console.log('the event', event)
    setButtonEl(event.currentTarget)
}

return (
    <>
        <IconButton iconName={"menu-hamburger"} size="s" onClick={handleClick} color={"midGray"}></IconButton>

рдирд┐рд░реНрдпрд╛рдд рдбрд┐рдлрд╝реЙрд▓реНрдЯ [readme, рдШрдЯрдХ];

рдФрд░ рдХрд╣рд╛рдирд┐рдпреЛрдВ / рдШрдЯрдХреЛрдВ / index.js рдореЗрдВ:
storiesOf('Components', module) .addDecorator(withKnobs) .add('Text', withReadme(...Menu))

@shiranZe рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ addon-readme рд╕рд╛рде рдПрдХ рд╕рдорд╕реНрдпрд╛ рд╣реИ - рд╢рд╛рдпрдж рд╡рд╣рд╛рдБ рдПрдХ рдореБрджреНрджрд╛ рджрд░реНрдЬ рдХрд░реЗрдВ?

рдЖрдкрдХреЗ рдЙрддреНрддрд░ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж @ рд╢реАрд▓рдорд╛рди ред рдореБрдЭреЗ рдирд╣реАрдВ рдкрддрд╛ рдХрд┐ рдХреНрдпрд╛ рд╕рдорд╕реНрдпрд╛ рд╣реИред рдореИрдВрдиреЗ addon-readme рдмрд┐рдирд╛ рдХреЛрд╢рд┐рд╢ рдХреА рдФрд░ рдЕрднреА рднреА рд╡рд╣реА рддреНрд░реБрдЯрд┐ рд╣реЛ рд░рд╣реА рд╣реИред рдХреНрдпрд╛ рдЖрдкрдХреЗ рдкрд╛рд╕ 5.2-рдмреАрдЯрд╛ рд╕реНрдЯреЛрд░реА рдмреБрдХ рдХрд╛ URL рд╣реИ?
рдореИрдВрдиреЗ https://storybooks-official.netlify.com/ (рдЕрдиреНрдп | рдбреЗрдореЛ / рдмрдЯрди) рдкрд░ рдПрдХ рдирдЬрд╝рд░ рдбрд╛рд▓рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХреА
рд▓реЗрдХрд┐рди рдореИрдВ рд╡рд╣рд╛рдБ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╣реБрдХ рдХреЗ рд╕рд╛рде рдЙрджрд╛рд╣рд░рдг рдирд╣реАрдВ рдорд┐рд▓ рд╕рдХрддрд╛ рд╣реИред

рдореЗрд░реЗ рдкрд╛рд╕ рдЕрднреА рднреА 5.2.0-beta.30 рд╕рд╛рде рд╕рдорд╕реНрдпрд╛ рд╣реИ рдФрд░ рдмрд╛рдд рдореЗрд░реЗ рд▓рд┐рдП рдХрд╛рдо рдХрд┐рдП рдЧрдП рдХрд┐рд╕реА рднреА рдкреНрд░рдХрд╛рд░ рдХреЗ рд╡рд░реНрдХрдЕрд░рд╛рдЙрдВрдб рдХреА рдирд╣реАрдВ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдореИрдВ knobs рдПрдбрдСрди рдХрд╛ рднреА рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВред

@shiranZe рд╣рдорд╛рд░реА рдиреЗрдЯрд▓рд┐рдлрд╝ рдХреА рддреИрдирд╛рддреА рдмрдВрдж рд╣реИ (cc @ndelangen) рд▓реЗрдХрд┐рди рдЖрдк next рд╢рд╛рдЦрд╛ рдкрд░ рд░реЗрдкреЛ рдХреА рдЬрд╛рдБрдЪ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕реЗ рд╡рд╣рд╛рдБ рдЖрдЬрд╝рдорд╛ рд╕рдХрддреЗ рд╣реИрдВред

@ рд╕реНрд░реЛрдд рд╕реВрддреНрд░реЛрдВ рдХрд╛ рдорд╛рдирдирд╛ тАЛтАЛрд╣реИ рдХрд┐ knobs рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд "рдкреВрд░реНрд╡рд╛рд╡рд▓реЛрдХрди рд╣реБрдХ" рд╕рдорд╕реНрдпрд╛ (cc @Hypnosphi) рдХрд╛ рдЗрд╕ рдореБрджреНрджреЗ рд╕реЗ рдХреЛрдИ рд▓реЗрдирд╛-рджреЗрдирд╛ рдирд╣реАрдВ рд╣реИ - рдХреЗрд╡рд▓ рдПрдХ рдЪреАрдЬ рдЬреЛ рдЙрдирдХреЗ рдкрд╛рд╕ рд╣реИ рд╡рд╣ рд╣реИ рд╣реБрдХ рдХреА рдЕрд╡рдзрд╛рд░рдгрд╛ред

@ рд╢реАрд▓рдорд╛рди рдереИрдВрдХреНрд╕ , рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рддреБрдо рд╕рд╣реА рд╣реЛред Btw рдореБрдЭреЗ рдкрддрд╛ рдЪрд▓рд╛ рдХрд┐ рдЗрд╕реЗ рдХреИрд╕реЗ рдкрд░реАрдХреНрд╖рдг рдФрд░ рддреНрд░реБрдЯрд┐ рд╕реЗ рдареАрдХ рдХрд┐рдпрд╛ рдЬрд╛рдП, рдХрд╕реНрдЯрдо рд╣реБрдХ рдХреЛ рдмрджрд▓ рджрд┐рдпрд╛ рдЬрд╛рдП:

export const useField = (id, updateField) => {
  const onChange = useCallback((event) => {
    const {
      target: { value },
    } = e;
    updateField(id, value);
  };

  return {
    onChange,
  };
}, []);

рд╕реЗрд╡рд╛

export const useField = (id, updateField) => {
  const onChange = (event) => {
    const {
      target: { value },
    } = e;
    updateField(id, value);
  };

  return {
    onChange,
  };
};

рдореВрд▓ рд░реВрдк рд╕реЗ рд╕рд┐рд░реНрдл useCallback рдХрд╛ рдЙрдкрдпреЛрдЧ рдпрд╣рд╛рдВ рд╕реЗ рд╣рдЯрд╛ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред рдореБрдЭреЗ рдпрдХреАрди рдирд╣реАрдВ рд╣реИ рдХрд┐ рдЕрдЧрд░ рдкрд╣рд▓рд╛ рд╕рдВрд╕реНрдХрд░рдг рдПрдХ рд╡реИрдз рд╣реБрдХ рдерд╛, рд▓реЗрдХрд┐рди рдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рдерд╛ред рдЬрдм Hooks can only be called inside the body of a function component рдХрд╣рддреЗ рд╣реИрдВ рдпрд╛ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЗ рдХрдИ рд╕рдВрд╕реНрдХрд░рдг рд╣реЛрддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рдереЛрдбрд╝рд╛ рднреНрд░рдорд┐рдд рд╣реЛрддрд╛ рд╣реИред

рдЖрдкрдХреЗ рдЙрдкрд░реЛрдХреНрдд рдЙрджрд╛рд╣рд░рдг рдореЗрдВ, useCallback рдХреЛ рдирд┐рдХрд╛рд▓рдиреЗ рдХреЗ рдмрд╛рдж, рдХреНрдпрд╛ рдЖрдк рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ useField рдореЗрдВ рдХрд┐рд╕реА рднреА рд╣реБрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВ? ЁЯдФ

рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рд╡рд╣рд╛рдБ рдХреБрдЫ рдореБрджреНрджреЛрдВ рдХреЗ рд╕рд╛рде рд╣реБрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ knobs рдХреЗ рд╕рд╛рде рд╣реИред рдЕрдЧрд░ рдХреЛрдИ рднреА рд╕рд░рд▓ рд░рд┐рдкреНрд░реЛ рдкреНрд░рджрд╛рди рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рддреЛ рдореБрдЭреЗ рдЗрд╕ рдкрд░ рдПрдХ рдирдЬрд╝рд░ рдбрд╛рд▓рдХрд░ рдЦреБрд╢реА рд╣реЛрдЧреА

@shilman рдХреНрдпрд╛ рдЖрдкрдиреЗ рдореЗрд░реЗ рджреНрд╡рд╛рд░рд╛ рдкрд╣рд▓реЗ рдкреЛрд╕реНрдЯ рдХрд┐рдП рдЧрдП рдЙрджрд╛рд╣рд░рдг рдХреА рдХреЛрд╢рд┐рд╢ рдХреА рд╣реИ? рдпрд╣рд╛рдБ рд╕реНрдирд┐рдкреЗрдЯ рд╣реИ:

storiesOf('Test', module).add('with text', () => {
  return React.createElement(() => {
    const [value, setValue] = React.useState(1);

    Knobs.button('Increase', () => setValue(prev => prev + 1));

    return <span>{value}</span>;
  });
});

рдкреБрд░рд╛рдиреЗ API рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП, рд▓реЗрдХрд┐рди рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рдирд╡реАрдирддрдо API рдореЗрдВ рдмрджрд▓рдирд╛ рдЖрд╕рд╛рди рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рдЖрдк рдореВрд▓ рдкреЛрд╕реНрдЯ рд╕реЗ рдЕрдкреЗрдХреНрд╖рд┐рдд рд╡реНрдпрд╡рд╣рд╛рд░ рдкрд╛ рд╕рдХрддреЗ рд╣реИрдВред

@zhenwenc FYI рдХреЛрдб рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди react-docgen-typescript-webpack-plugin рджреНрд╡рд╛рд░рд╛ рдкреНрд░рджрд╛рди рдХрд┐рдП рдЧрдП рдбреЙрдХреНрд╕ рдХреЗ рдЙрдкрдпреЛрдЧ рдХреЛ рддреЛрдбрд╝рддрд╛ рд╣реИред

рд╡рд░реНрдХрдЕрд░рд╛рдЙрдВрдб рдЕрдиреНрдп рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреЗ рд╕рд╛рде рдереЛрдбрд╝рд╛ рднрдВрдЧреБрд░ рдФрд░ рдкрд░рд╕реНрдкрд░ рд╡рд┐рд░реЛрдзреА рд▓рдЧрддрд╛ рд╣реИред рдПрдХ рд╡рд┐рдХрд▓реНрдк рдХреЗ рд░реВрдк рдореЗрдВ, рдХреНрдпрд╛ рдХрд┐рд╕реА рдХреЗ рдкрд╛рд╕ рдЕрдиреБрднрд╡ рд╣реИ ?: https://github.com/Sambego/storybook-state

рдпрд╣рд╛рдБ рдЙрди рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдЬреЛ рддреНрд░реБрдЯрд┐ рд╕рдВрджреЗрд╢ рдХреЛ рджреЗрдЦрддреЗ рд╣реИрдВ:

рдореБрдЭреЗ рдпрд╣ рддреНрд░реБрдЯрд┐ рддрдм рд╣реБрдИ рдЬрдм рд╣реБрдХ рдХреЗ рд╕рд╛рде рдПрдХ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдШрдЯрдХ рдХреЗ рд▓рд┐рдП рдПрдХ рд╡рд░реНрдЧ рдШрдЯрдХ рдХреЛ рдмрджрд▓рдирд╛ рдФрд░ useState рдЧрд▓рдд рддрд░реАрдХреЗ рд╕реЗ @storybook/addons рд╕реЗ рдЖрдпрд╛рдд рд╣реЛ рд░рд╣рд╛ рдерд╛ред рдореБрдЭреЗ рдЗрд╕рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ react рдмрдЬрд╛рдп @storybook/addons ... рдСрдЯреЛ-рдЖрдпрд╛рдд рд╡рд┐рдлрд▓ рд╣реЛрдиреЗ рд╕реЗ рд╣реБрдИред

рдмрд╕ рдПрдХ рд╕реНрдирд┐рдкреЗрдЯ рдХреЗ рд▓рд┐рдП @ рдмреЛрд░рд┐рдпрд╕ рдХреЗ рдЕрдиреБрд░реЛрдз рдХрд╛ рдЬрд╡рд╛рдм

рдореЗрд░реЗ .storybook / config.js рдХреЗ рд▓рд┐рдП рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЬреЛрдбрд╝рдирд╛ рдореЗрд░реЗ рд▓рд┐рдП рдХрд╛рдо рдХрд┐рдпрд╛
addDecorator((Story) => <Story />)

@emjaksa рдХреНрдпрд╛ рдЖрдк рдЗрд╕ рдХрд╛ рдПрдХ рдЯреБрдХрдбрд╝рд╛ рдкреНрд░рджрд╛рди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ?

diff --git a/.storybook/config.js b/.storybook/config.js
--- a/.storybook/config.js
+++ b/.storybook/config.js
@@ -1,6 +1,9 @@
-import { configure } from '@storybook/react';
+import { configure, addDecorator } from '@storybook/react';
+import React from 'react';

 // automatically import all files ending in *.stories.js
 configure(require.context('../stories', true, /\.stories\.js$/), module);
+
+addDecorator((Story) => <Story />);

рдкрд░рд┐рдгрд╛рдо (рдкреВрд░рд╛ .storybook/config.js ):

import { configure, addDecorator } from '@storybook/react';
import React from 'react';

// automatically import all files ending in *.stories.js
configure(require.context('../stories', true, /\.stories\.js$/), module);

addDecorator((Story) => <Story />);

рдореИрдВ рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рдШрдЯрдХ рдореЗрдВ рдЕрдВрджрд░ рдХрд╣рд╛рдирд┐рдпреЛрдВ, рд▓реЗрдХрд┐рди рд░реИрдкрд┐рдВрдЧ рдХрд╣рд╛рдирд┐рдпреЛрдВ рдХрд╛рдо рдХрд░ рд╣реБрдХ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдирд╣реАрдВ рдпрдХреАрди рд╣реИ рдХрд┐ рдЕрдЧрд░ рдпрд╣ рд╕рдмрд╕реЗ рдЕрдЪреНрдЫрд╛ рддрд░реАрдХрд╛ рд╣реИ рдкрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд╣реИ рдХрд░ рд░рд╣рд╛ рд╣реВрдБ <Story /> рдШрдЯрдХ рдХреЗ рд╕рд╛рде рдпрд╣рд╛рдБ рдХрд╛рдо рдХрд┐рдпрд╛ "@storybook/react": "^5.2.6", ред

рдРрд╕рд╛ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ, рдЬрдм рднреА рдореИрдВрдиреЗ рдПрдХ рдиреЙрдм (рдпрд╛рдиреА: рдмреВрд▓рд┐рдпрди) рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд┐рдпрд╛, рддреЛ рдЗрд╕рдиреЗ рдкрд╣рд▓реЗ рд░реЗрдВрдбрд░ рдкрд░ рдХрд╛рдо рдХрд┐рдпрд╛, рд▓реЗрдХрд┐рди рдЗрд╕рдХреЗ рдмрд╛рдж рд░реЗрдВрдбрд░ рдХрд░рдирд╛ рдмрдВрдж рдХрд░ рджрд┐рдпрд╛ред рдЙрдкрд░реЛрдХреНрдд рд╕рдорд╛рдзрд╛рди рддрдп рд╣реИ рдХрд┐ Btw, рдореБрдЭреЗ рдпрдХреАрди рдирд╣реАрдВ рд╣реИ рдХрд┐ рд╕реНрдЯреЛрд░реАрдмреБрдХ рдореЗрдВ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╣реБрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЕрдЪреНрдЫрд╛ рд╣реИ, рдмрд╕ рдЕрдЧрд░ рд╕рдВрднрд╡ рд╣реЛ рддреЛ рд╕рдм рдХреБрдЫ рдирдХрд▓реА рдХрд░реЗрдВ, рдпрд╣ рд╢рд╛рдпрдж рдЗрд╕ рддрд░рд╣ рд╕реЗ рдмреЗрд╣рддрд░ рд╣реИред

рдмрдЧ рдХрд╛ рд╡рд░реНрдгрди рдХрд░реЗрдВ

рдПрдХ рдХрд╣рд╛рдиреА рдореЗрдВ рд╕реАрдзреЗ рд╣реБрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, Hooks can only be called inside the body of a function component рд╕рд╛рде рд╡рд┐рдлрд▓ рд╣реЛрддрд╛ рд╣реИред

рдкреНрд░рдЬрдирди рдХрд░рдирд╛

рдЙрджрд╛рд╣рд░рдг рдХреЛрдб:

import React from 'react'

import { storiesOf } from '@storybook/react'

const stories = storiesOf('Hooks test', module)

const TestComponent: React.FC = () => {
  const [state, setState] = React.useState(5)
  return (
    <button onClick={() => setState(state + 1)}>
      {state}
    </button>
  )
}

stories.add('this story works', () => <TestComponent />)

stories.add('this story fails', () => {
  const [state, setState] = React.useState(5)
  return (
    <button onClick={() => setState(state + 1)}>
      {state}
    </button>
  )
})

рдЕрдкреЗрдХреНрд╖рд┐рддреН рд╡реНрдпрд╡рд╣рд╛рд░
рдкрд╣рд▓реА рдХрд╣рд╛рдиреА рдареАрдХ рдХрд╛рдо рдХрд░рддреА рд╣реИ, рджреВрд╕рд░реА рдХрд╣рд╛рдиреА рдкреНрд░рд╛рд░рдВрднрд┐рдХ рд░реЗрдВрдбрд░ рдкрд░ рд╡рд┐рдлрд▓ рд╣реЛрддреА рд╣реИ

рд╕рдВрд╕реНрдХрд░рдгреЛрдВ
@storybook/[email protected]
[email protected]
[email protected]

======================================

рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдШрдЯрдХреЛрдВ рдХреЛ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рддреАрд░ рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рди рдХрд░реЗрдВред
рдиреАрдЪреЗ рджрд┐рдП рдЧрдП рдЙрджрд╛рд╣рд░рдгреЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рдХреЗ рд░реВрдк рдореЗрдВ рдХрд░реЗрдВ:

function MyComponent(props) {
  const [states, setStates] = React.useState({ value: '' });

  return (
    <input
      type="text"
      value={states.value}
      onChange={(event) => setStates({ value: event.target.value })}
    />
  );
}

рдпрд╛

//IMPORTANT: Repeat the function name

const MyComponent = function MyComponent(props) { 
  const [states, setStates] = React.useState({ value: '' });

  return (
    <input
      type="text"
      value={states.value}
      onChange={(event) => setStates({ value: event.target.value })}
    />
  );
};

рдпрджрд┐ рдЖрдкрдХреЛ "рд░реЗрдл" (рд╢рд╛рдпрдж рдЫреЛрд░реЛрдВ рдореЗрдВ) рдХреА рд╕рдорд╕реНрдпрд╛ рд╣реИ, рддреЛ рд╕рдорд╛рдзрд╛рди рдлреЙрд░рд╡рд░реНрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реИ ():

// IMPORTANT: Repeat the function name
// Add the "ref" argument to the function, in case you need to use it.

const MyComponent = React.forwardRef( function MyComponent(props, ref) {
  const [states, setStates] = React.useState({ value: '' });

  return (
    <input
      type="text"
      value={states.value}
      onChange={(event) => setStates({ value: event.target.value })}
    />
  );
});

рдпрд╣ MDX рдореЗрдВ рдХреИрд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ?

рд▓реЗрдХрд┐рди рдЕрднреА рднреА рддреНрд░реБрдЯрд┐ рд╣реЛ рд░рд╣реА рд╣реИ:
рд░рд┐рдПрдХреНрдЯ рд╣реВрдХ "рдпреВрдЬрд╝рд╕реНрдЯреНрд░реЗрдЯ" рдХреЛ рдлрдВрдХреНрд╢рди "рдХрдВрдкреЛрдиреЗрдВрдЯ" рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬреЛ рди рддреЛ рд░рд┐рдПрдХреНрдЯ рдлрдВрдХреНрд╢рди рдХрдВрдкреЛрдиреЗрдВрдЯ рд╣реИ рдФрд░ рди рд╣реА рдХрд╕реНрдЯрдо рд░рд┐рдПрдХреНрдЯ рд╣реБрдХ рдлрдВрдХреНрд╢рди
https://github.com/storybookjs/storybook/issues/5721#issuecomment -518225880

рдореИрдВ рдпрд╣ рдПрдХ рд╣реА рдореБрджреНрджрд╛ рдерд╛ред рдирд╛рдорд╛рдВрдХрд┐рдд рдХрд╣рд╛рдиреА рдирд┐рд░реНрдпрд╛рдд рдХреЛ рдареАрдХ рдХрд░рдирд╛ рд╣реИред

 'рд░рд┐рдПрдХреНрд╢рди' рд╕реЗ рдЖрдпрд╛рдд рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛;
 Foo рд╕реЗ рдЖрдпрд╛рдд рдХрд░реЗрдВред / .Foo ';

 рдирд┐рд░реНрдпрд╛рдд рдбрд┐рдлрд╝реЙрд▓реНрдЯ {
 рд╢реАрд░реНрд╖рдХ: 'рдлреВ';
 };

 Export const рдмреБрдирд┐рдпрд╛рджреА = () => <Foo />

рдбреЙрдХреНрд╕ рдХрд╛ рдХрд╣рдирд╛ рд╣реИ рдХрд┐ рдХреИрдкрд┐рдЯрд▓рд╛рдЗрдЬрд╝реЗрд╢рди рдХреА рд╕рд┐рдлрд╛рд░рд┐рд╢ рдХреА рдЧрдИ рд╣реИ, рд▓реЗрдХрд┐рди рдпрджрд┐ рдЖрдк рдЪрд╛рд╣рддреЗ рд╣реИрдВ рдХрд┐ рдЪреЗрддрд╛рд╡рдиреА рджреВрд░ рд╣реЛ рдЬрд╛рдП рддреЛ рдпрд╣ рдЖрд╡рд╢реНрдпрдХ рд╣реИред

рдореЗрд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рд╕рдорд╕реНрдпрд╛ рдпрд╣ рдереА рдХрд┐ рдореИрдВ рдЕрдкрдиреЗ рджреНрд╡рд╛рд░рд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЬрд╛ рд░рд╣реЗ рд╣реБрдХ рдХреЛ рдЖрдпрд╛рдд рдХрд░рдирд╛ рднреВрд▓ рдЧрдпрд╛ рдерд╛ред

рдореЗрд░реЗ .storybook / config.js рдХреЗ рд▓рд┐рдП рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЬреЛрдбрд╝рдирд╛ рдореЗрд░реЗ рд▓рд┐рдП рдХрд╛рдо рдХрд┐рдпрд╛

addDecorator((Story) => <Story />)

@emjaksa Thanx! рд╕реНрдЯреЛрд░реАрдмреБрдХ рдкрд░ рдкрд░реАрдХреНрд╖рдг рдФрд░ рдареАрдХ рдХрд╛рдо v5.3ред

рдореЗрд░реЗ рдкрд╛рд╕ рдПрдХ рд╣реА рдореБрджреНрджрд╛ рдерд╛, рдореЗрд░реЗ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдШрдЯрдХ рдореЗрдВ useState(value) рдФрд░ value рдиреЗ Knobs рд╕реЗ рдирдП рдореВрд▓реНрдп рдХреЛ рдлрд┐рд░ рд╕реЗ рдкреНрд░рд╕реНрддреБрдд рдирд╣реАрдВ рдХрд┐рдпрд╛, рдпрд╣ рдореБрджреНрджрд╛ рдЙрдкрдпреЛрдЧ рдХреЗ рдХрд╛рд░рдг рд╣реЛрддрд╛ рд╣реИ:

рд░рд┐рдПрдХреНрдЯ рдбреЙрдХреНрд╕ рд╕реЗ:
Screen Shot 2020-08-07 at 19 00 04

рдХрд╛рдо рдХрд░ рд╕рдорд╛рдзрд╛рди рд╕реНрдЯреЛрд░реАрдмреБрдХ v5.3:

рдкреНрд░рд┐рд╡реНрдпреВ рдЕрдкрдбреЗрдЯ рдХрд░реЗрдВред js

.storybook/preview.js
import React from 'react'; // Important to render the story
import { withKnobs } from '@storybook/addon-knobs';
import { addDecorator } from '@storybook/react';

addDecorator(withKnobs);
addDecorator(Story => <Story />); // This guy will re-render the story

рдФрд░ main.js рдХреЛ рднреА рдЕрдкрдбреЗрдЯ рдХрд░реЗрдВ

.storybook/main.js
module.exports = {
  stories: ['../src/**/*.stories.jsx'],
  addons: [
    '@storybook/preset-create-react-app',
    '@storybook/addon-knobs/register', // Attention to this guy
    '@storybook/addon-actions',
    '@storybook/addon-links',
  ],
  webpackFinal: async config => {
    return config;
  },
};


тЭУ
рдХреНрдпрд╛ рдХрд┐рд╕реА рдХреЛ рдкрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдЖрдХрд░реНрд╖рдХ рдбреЗрдХреЛрд░реЗрдЯрд░ рд╣реБрдХ рдХрд╛рдо рдХреНрдпреЛрдВ рдХрд░рддрд╛ рд╣реИ?

`` `TSX
SomeComponent.decorators = [(рдХрд╣рд╛рдиреА) => ]

@tmikeschu рдпрд╣ рдЗрд╕рд▓рд┐рдП рд╣реИ рдХреНрдпреЛрдВрдХрд┐ <Story /> React.createElement рдореЗрдВ рдХреЛрдб рдХреЛ рд▓рдкреЗрдЯрддрд╛ рд╣реИ рдЬреЛ рд╣реБрдХ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╣реИред

@ рд╢рд┐рд▓реНрдкреА рдзрдиреНрдпрд╡рд╛рдж!

рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕

рд╕рдВрдмрдВрдзрд┐рдд рдореБрджреНрджреЛрдВ

wahengchang picture wahengchang  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

tirli picture tirli  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

MrOrz picture MrOrz  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

miljan-aleksic picture miljan-aleksic  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

alexanbj picture alexanbj  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ