Matt Parrilla
Matt Parrilla

Reputation: 3221

How to Identify components that trigger changes to state in React+Flux?

What is the canonical React+Flux way to ID components that trigger changes to state?

I've got an application that allows a user to create palettes using the HSL color space.

Here's the component structure of my app:

Container (this component gets state and passes it down the chain)
 | PalettePicker
   | ColorPicker
     | Slider (this component fires action)
     | Slider
     | Slider
   | (As many ColorPickers as colors)
 | ImageSamples (not relevant, but dependent on palette)

Here's a look at the ColorPicker component:

ColorPicker component

Each ColorPicker contains 3 Slider components which trigger events that update the store. The store then updates the palette and passes the entire palette down to the Container component, which passes it down as props to its children components.

Here's my function that handles a slider change event in my Store (I'm using Reflux):

sliderChange: function(newValue) {
    var modifiedPalette = this.palette;
    modifiedPalette[newValue.colorIndex][newValue.colorPartsIndex] = newValue.value;
    this.trigger(modifiedPalette)
}

My palette is an array of HSL color values, so something like:

[ [350, 100, 50], [340, 100, 40], ... ]

A "color" is one of the 3-item arrays above and I'm calling each item in the color array a "color part" since it represents either the H, S, or L of the color.

Passing the color and color part index down as a prop seems inelegant. I'm currently building components like this:

colorPickers = palette.map(function(color, i) {
    return (
        <ColorPicker 
             key={i}
             colorIndex={i}
             color={color}
        />
    )
});

As far as I can tell, I need to pass colorIndex as a prop so that my child component can know which color in the palette it maps to so that I can pass that knowledge on to the store.

What's the idiomatic React+Flux way to do this?

Upvotes: 1

Views: 340

Answers (1)

lyosef
lyosef

Reputation: 6222

I would suggest not letting the ColorPicker component call any action itself, but pass it as an "onChange" prop. It doesn't need to know what index it is. You can bind the onChange function so that it will pass the index:

colorPickers = palette.map(function(color, i) { 
   return ( 
      <ColorPicker key={i} 
          onChange={this.changeColor.bind(this, i)} 
          color={color} 
      /> 
   ) 
});

The changeColor function looks like this:

changeColor : function(colorIndex,  colorArray) {...}

It should receive the whole color (the array) and fire the appropriate Reflux action with it and the index. That way the ColorPicker only have to fire the onChange function with the new color that changed.

Do the same trick for every slider inside the color picker. Pass it an onChange function that is already bounded to its partIndex. When that function is triggered, The ColorPicker should construct a new color array, and call its own onChange prop.

Hope it was clear enough. The motivation is - every component should get a simple callback function and output only what it is responsible for. It doesn't need to know any other details. Instead of passing more and more useless index props all the way down, just pass bounded callbacks. It will simplify your components and will let your high-level component deal with the details of constructing the Flux action itself.

Upvotes: 1

Related Questions