I am using storybook
( this ) to play with my components in isolation. I want to mock all the flux cycle (that in the full app it is done with the help of redux
) and update a property using a simple object in the story, but I am missing something.
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}
/>
)
}
I expect the value
prop of <ColorPicker />
to be updated when the onChange
is called; I can see the value of colorPickerState.color
being updated correctly, but the component does not re-render.
What am I missing?
You can write a dummy-component which will render the real story component inside it, and then you get to have that dummy-component 's state
property.
In the below example I'm using knobs addon in a story of a Slider component
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)
}
return <StoryComp {...props} />
}
);
You can use an addon to achieve this: https://github.com/Sambego/storybook-state
So your code would look like:
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>
)
}
I would try employing the useState
hook from react - updating state values via its setters seems to have the effect of re-rendering your storybook component.
I had a similar problem where my data input form's state and event handling (including complex validation) is done in globally, up a level in the component tree. I was able to get a working demo of this component and its complex validation by writing a simple event handler to pass along to my component.
Do note that my code is in Typescript. I am pretty new to the React world so this might not be perfect.
// 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}
/>
);
};
In the latest version (v6) this functionality calls Args . Also you can use argTypes to see action's logs or specify props.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.