Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to update components props in storybook

Tags:

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?

like image 649
ciaoben Avatar asked Aug 28 '17 11:08

ciaoben


People also ask

How do you update a component prop?

A component cannot update its own props unless they are arrays or objects (having a component update its own props even if possible is an anti-pattern), but can update its state and the props of its children.

Does props change component update?

React components automatically re-render whenever there is a change in their state or props. A simple update of the state, from anywhere in the code, causes all the User Interface (UI) elements to be re-rendered automatically.

Can props be updated or read only?

“Props” is a special keyword in React, which stands for properties and is being used for passing data from one component to another. Furthermore, props data is read-only, which means that data coming from the parent should not be changed by child components.


2 Answers

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} />
    }
);
like image 101
vsync Avatar answered Oct 29 '22 05:10

vsync


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>
  )
}
like image 44
smurf Avatar answered Oct 29 '22 03:10

smurf