casesandberg/react-color

Color selection doesn't work with React 18

bruceharrison1984 opened this issue · 2 comments

Using any of the color pickers doesn't seem to work in React 18. Using the slider, the value changes, but the slider doesn't move. Using the SketchPicker, again I can select a color, but the selector icon never moves.

No errors in console, and the control technically works because events fire, but the selector doesn't move to indicate that I actually selected anything.

I tried downgrading to 2.17, but the issue persists.

It seems that you must use class components in order for selection to work
see newer reply for functional components

Swapping over to class components instead of functional components immediately fixed my selection issue. I tried this with the Sketch and Slider components and both worked with React 18 when wrapped within a class component.

For example, the Slider can be used as follows:

// ColorSlider.tsx
import { Color, ColorChangeHandler, SliderPicker } from 'react-color';
import React from 'react';

interface SliderProps {
  color: Color;
  onChange: ColorChangeHandler;
}

class ColorSlider extends React.Component<SliderProps> {
  state = {
    color: this.props.color,
  };

  handleChange: ColorChangeHandler = (color, event) => {
    this.setState({ color: color.rgb }); // update internal state
    this.props.onChange(color, event); // send the new value 'up' to the parent
  };

  render() {
    return (
      <SliderPicker color={this.state.color} onChange={this.handleChange} />
    );
  }
}

export default ColorSlider;

and usage within a parent functional components is typical:

// parentComponent.tsx (functional component)
<ColorSlider
  color={userProfile?.event_color || '#7e8da3'}
  onChange={(color: ColorResult) =>
    setValue('eventColor', color.hex, { shouldDirty: true })
  }
/>

I used version 2.19.3 for this. Any attempt to directly use components in this library within a functional component triggered the no selection problem, but wrapping it in a class component works. Slightly altering the above example to use whichever color picker component you want should work just fine.

Shame this repo is dead, it's a good library!

Iterating on this a bit more, these components don't have any internal state. You can use them directly within functional components, but you must maintain the state for them:

// functional-component.tsx
const ProfileModal = (({ userProfile }: ProfileModalProps) => {
  const [eventColor, setEventColor] = useState<Color>(
    userProfile?.event_color || '#7e8da3'
  );
  return (
  <SliderPicker
    color={eventColor}
    onChange={(color) => {
      setEventColor(color.hex);
      // send value somewhere else here... maybe setValue for react-hook-form
    }}
  />
);

This is probably obvious to React vets, but was a surprise for a newbie like me whose been pampered with functional components, hooks, and libraries that make liberal use of internal state.