Как обновить компоненты реквизита в сборнике рассказов
Я использую storybook
( это) играть с моими компонентами в изоляции. Я хочу издеваться над всем циклом потока (что в полном приложении это делается с помощью redux
) и обновить свойство, используя простой объект в истории, но я что-то упустил.
storiesOf('Color picker', module).add('base', () => {
let colorPickerState = {
changeColor: function(data) {
this.color = data.color
},
color: '#00aced'
}
return (
<ColorPicker
name="color"
onChange={colorPickerState.changeColor.bind(colorPickerState)}
value={colorPickerState.color}
/>
)
}
Я ожидаю value
опора <ColorPicker />
обновляться, когда onChange
называется; Я вижу ценность colorPickerState.color
обновляется правильно, но компонент не выполняет повторную визуализацию.
Что мне не хватает?
5 ответов
Вы можете написать фиктивный компонент, который будет отображать реальный компонент истории внутри него, а затем вы получите этот фиктивный компонентstate
имущество.
В приведенном ниже примере я использую аддоны knobs в истории компонента Slider
stories.addDecorator(withKnobs)
.add('Slider', () => {
// create dummy component that wraps the Slider and allows state:
class StoryComp extends React.Component {
constructor( props ){
super(props);
this.state = {
value : this.props.value || 0,
}
}
onValueChange = value => this.setState({ value })
render(){
const props = {.
...this.props,
onValueChange:this.onValueChange, // <--- Reason "StoryComp" is needed
value:this.state.value // <--- Reason "StoryComp" is needed
}
return <Slider {...props} />
}
};
// knobs (customaziable props)
const widthKnobOptions = {
range : true,
min : 200,
max : 1500,
step : 1
}
const props = {
value : number('value', 200000),
min : number('min', 100),
step : number('step', 1000),
max : number('max', 1000000),
width : number('width', 700, widthKnobOptions)
};
const WrappedComponent = storybookWrapper(StoryComp, props);
return <WrappedComponent />
}
);
Вы можете использовать аддон для достижения этой цели: https://github.com/Sambego/storybook-state
Итак, ваш код будет выглядеть так:
import { State, Store } from '@sambego/storybook-state';
const store = new Store({
value: '#00aced',
});
storiesOf('Color picker', module).add('base', () => {
return (
<State store={store}>
<ColorPicker
name="color"
onChange={(data) => store.set({ value: data.color })}
/>
</State>
)
}
Я бы попробовал использовать
У меня была аналогичная проблема, когда состояние моей формы ввода данных и обработка событий (включая сложную проверку) выполнялись глобально, выше уровня в дереве компонентов. Я смог получить рабочую демонстрацию этого компонента и его сложную проверку, написав простой обработчик событий для передачи моему компоненту.
Обратите внимание, что мой код находится в Typescript. Я новичок в мире React, так что это может быть не идеально.
// Things defined elsewhere: IComponentProps, IValidationResult, IFormInput, EntryForm
// useState and useCallbac comes from react
export const MyComponentDemo = (args: IComponentProps) => {
const [validations, setValidations] = useState<IValidationResult[]>([]);
const [theForm, setTheForm] = useState<IFormInput>(
{
...args.formValues,
// set other interesting default form values here
}
);
const dummyValidationMethod = useCallback((form: IFormInput) => {
let validations : IValidationResult[] = [];
// Do validation using data from form
setValidations(validations);
setTheForm(form);
}, []);
return (
<EntryForm
{...args}
formValues={theForm}
onValidation={dummyValidationMethod}
validatedLocations={validations}
/>
);
};
Для тех, кто ищет решение с помощью современного React и Storybook.
Допустим, мы переписали ColorPicker, чтобы он стал функциональным компонентом в React, который получает состояние от родительского компонента со следующим интерфейсом:
interface ColorPickerProps {
name: string
useColorPickerState: [value: string, setValue: (value: string) => void ] // useState() array passed from parent (we're replacing onChange and value props with this)
}
React не позволяет использовать хуки вне функций, поэтому мы можем просто создать функциональный компонент-оболочку, чтобы состояние работало так, как ожидается в сборнике рассказов:
import { StoryObj, Meta } from '@storybook/react'
import ColorPicker, { ColorPickerProps } from 'location-of-your-component'
import { useState } from 'react'
function ColorPickerWrapper({ name }: Pick<ColorPickerProps, 'name'>) {
const [value, setValue] = useState('#0ed0ac')
return <ColorPicker name={name} useColorPickerState=[value, setValue] />
}
const meta: Meta<typeof ColorPicker> = {
title: 'Components/ColorPicker',
component: ColorPickerWrapper
}
export default meta
type Story = StoryObj<typeof ColorPicker>
export const Base: Story = {
args: {
name: 'color'
}
}
Я понимаю, что это другой случай, чем вопрос ОП, но, надеюсь, это поможет кому-то это искать :)
В последней версии (v6) эта функция вызывает Args . Также вы можете использовать argTypes, чтобы просмотреть журналы действий или указать реквизиты.