Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save janjakubnanista/d4ea4249f76a48b93c8fc914d6c16833 to your computer and use it in GitHub Desktop.
Save janjakubnanista/d4ea4249f76a48b93c8fc914d6c16833 to your computer and use it in GitHub Desktop.
// Approach 2: let's define a whole new component type and let it handle the item rendering completely
//
// This way we are free to handle the rendering and selecting/deselecting anyway we want
export interface SelectProps<T> {
// ... previous props
itemComponent: React.ComponentType<SelectItemProps<T>>;
}
// These will be the props of our new item component
export interface SelectItemProps<T> {
selected: boolean;
value: T;
onToggle: (value: T) => void;
}
export function Select<T>({ items, value, idFromValue, itemComponent: ItemComponent, onChange }: SelectProps<T>) {
const selectedId = value === undefined ? undefined : idFromValue(value);
const isSelected = (id: string | number) => id === selectedId;
const handleToggle = (value: T) => onChange?.(isSelected(idFromValue(value)) ? undefined : value);
return <div>
{items.map(item => {
const id = idFromValue(item);
const selected = isSelected(id);
// We need to rename the itemComponent prop to something that starts
// with an uppercase letter because if we write
//
// <itemComponent ... />
//
// React is going to think we want to use a HTML tag called "itemComponent"
return <ItemComponent key={id} value={item} selected={selected} onToggle={handleToggle} />;
})}
</div>;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment