рдмрдЧ рдХрд╛ рд╡рд░реНрдгрди рдХрд░реЗрдВ
рдПрдХ рдХрд╣рд╛рдиреА рдореЗрдВ рд╕реАрдзреЗ рд╣реБрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, 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]
рдпрдХреАрди рдирд╣реАрдВ рд╣реЛрддрд╛ рдХрд┐ рдпрд╣ рдПрдХ рдмрдЧ рд╣реИред рдореЗрд░рд╛ рдорд╛рдирдирд╛ тАЛтАЛрд╣реИ, рдФрд░ рдореИрдВ рдЧрд▓рдд рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, 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
рд╕рд╛рде рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ:
рдпрд╣ рдЗрд╕ рд╕рдорд╛рдзрд╛рди рдХреЛ рдЕрдиреБрдкрдпреЛрдЧреА рдмрдирд╛рддрд╛ рд╣реИред рдХреЛрдИ рд╡рд┐рдЪрд╛рд░? рд╕реНрдЯреЛрд░реАрдмреБрдХ 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 рд╕реЗ рдирдП рдореВрд▓реНрдп рдХреЛ рдлрд┐рд░ рд╕реЗ рдкреНрд░рд╕реНрддреБрдд рдирд╣реАрдВ рдХрд┐рдпрд╛, рдпрд╣ рдореБрджреНрджрд╛ рдЙрдкрдпреЛрдЧ рдХреЗ рдХрд╛рд░рдг рд╣реЛрддрд╛ рд╣реИ:
рд░рд┐рдПрдХреНрдЯ рдбреЙрдХреНрд╕ рд╕реЗ:
рдХрд╛рдо рдХрд░ рд╕рдорд╛рдзрд╛рди рд╕реНрдЯреЛрд░реАрдмреБрдХ 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
рдореЗрдВ рдХреЛрдб рдХреЛ рд▓рдкреЗрдЯрддрд╛ рд╣реИ рдЬреЛ рд╣реБрдХ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╣реИред
@ рд╢рд┐рд▓реНрдкреА рдзрдиреНрдпрд╡рд╛рдж!
рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА
рд╣рдордиреЗ рдПрдХ рд╣реА рд╕рдорд╕реНрдпрд╛ рдХрд╛ рдЕрдиреБрднрд╡ рдХрд┐рдпрд╛ рд╣реИ, рдФрд░ рдпрд╣ рдПрдХ рд╕рд░рд▓ рд╣реИрдХ рд╣реИ рдЬрд┐рд╕реЗ рд╣рдо рдЗрд╕реЗ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд░рддреЗ рд╣реИрдВред
рдореИрдВ рдорд╛рдирддрд╛ рд╣реВрдВ рдХрд┐ рдпрд╣ рдмрд┐рдирд╛ рд╣реИрдХ рдХреЗ рдореВрд▓ рд░реВрдк рд╕реЗ рд╕рдорд░реНрдерд┐рдд рд╣реЛрдирд╛ рдмреЗрд╣рддрд░ рд╣реЛрдЧрд╛ред рдпрджрд┐ рдЕрдиреБрдЪрд░ рднреА рд╕рд╣рдордд рд╣реИрдВ, рддреЛ рд╢рд╛рдпрдж рдореБрдЭреЗ рдкреАрдЖрд░ PR рдХреЗ рд╕рд╛рде рдЖрдиреЗ рдХреЗ рд▓рд┐рдП рдХреБрдЫ рд╕рдордп рдорд┐рд▓ рд╕рдХрддрд╛ рд╣реИред