Home

The API contract needs to be cohesive

Problem

Today I refactored a React component that allows:

  • selecting from a list of options
  • create a new option if you can't find what you looked for in the list of options

Live example here

The initial implementation was based off an example found on the Material UI documentation website. Link here

// Before refactoring
type OptionType = {label: string, value: string}
type ComboBoxProps = {
options: OptionType[],
onValueChange: string => null
}
ComboBox: FC<ComboBoxProps> = ({
label,
options,
onValueChange,
}) => {
/*implementation here*/
}

I had 2 issues with it

the API (aka props) wasn't cohesive

You passed in a list of options but the callback is named onValueChange. I would reuse the concept of the option given it's already used in the options array

the API didn't provide what the user of this component would expect

This component needs 2 event handlers:

  • event 1: when you select an existing option
  • event 2: when you create a new option

Reasons for 2 event handlers:

  • The user of this component will likely need to distinguish between these 2 events. When user creates a new option (i.e. event 2) the developer will likely need to make a backend call to create this option If you provide only 1 event handler then the developer using the combobox will need to handle that logic himself
  • having 2 event handlers documents what the purpose is of the react component. By having 2 event handlers onCreate and onSelect you emphasise the use case for this React component (i.e. select or create in 1 component)
// After refactoring
type OptionType = {label: string, value: string}
type ComboBoxProps = {
options: OptionType[],
onOptionSelect: OptionType => null,
onOptionCreate: OptionType => null
}
ComboBox: FC<ComboBoxProps> = ({
label,
options,
onOptionSelect,
onOptionCreate
}) => {
/*implementation here*/
}