©Sergey Emelyanov 2025 | Alle Rechte vorbehalten
Wrapper-Komponenten sind ein mächtiges Werkzeug, um Drittanbieter-Bibliotheken gekapselt und anpassbar zu integrieren. In diesem Artikel zeige ich anhand eines DatePicker-Beispiels, wie Sie durch gezieltes Wrapping Wiederverwendbarkeit, Erweiterbarkeit und Austauschbarkeit erreichen.
Angenommen, Sie nutzen react-datepicker
in Ihrem Projekt. Direkte Verwendung führt zu:
// Fragiler Code ohne zentrale Steuerung
<DatePicker
dateFormat="yyyy/MM/dd"
onChange={handleChange}
// ... 20 weitere Props
/>
Nachteile:
Hier kommt unsere DateField
-Komponente ins Spiel:
import DatePicker, { ReactDatePickerProps } from 'react-datepicker';
interface DateFieldProps extends ReactDatePickerProps {
module: Module;
field: string;
errors: FieldErrors;
}
export const DateField = ({
module,
field,
errors,
...datePickerProps
}: DateFieldProps) => {
const [date, setDate] = useState<Date | null>(null);
return (
<div className="mb-3">
<Form.Label>
<FormattedMessage id={`${module.name}.${field}`} />
</Form.Label>
<DatePicker
{...datePickerProps}
selected={date}
onChange={setDate}
className={`form-control ${errors[field] ? 'is-invalid' : ''}`}
/>
{errors[field] && (
<div className="invalid-feedback">
{errors[field].message}
</div>
)}
</div>
);
};
Key Features:
react-intl
react-hook-form
...datePickerProps
)Unsere Testsuite sichert die Funktionalität:
describe('DateField', () => {
test('Rendering mit Label und Validierungsfehler', () => {
const { getByLabelText, getByText } = render(
<DateField
module={{ name: 'sales' }}
field="deliveryDate"
errors={{ deliveryDate: { message: 'Ungültiges Datum' } }}
/>
);
expect(getByLabelText('Delivery Date')).toBeInTheDocument();
expect(getByText('Ungültiges Datum')).toBeInTheDocument();
});
test('Datumsänderung triggert Callback', () => {
const mockOnChange = jest.fn();
const { getByRole } = render(
<DateField
module={{ name: 'sales' }}
field="deliveryDate"
onChange={mockOnChange}
/>
);
fireEvent.change(getByRole('textbox'), {
target: { value: '2024-03-15' }
});
expect(mockOnChange).toHaveBeenCalledWith('deliveryDate', '2024-03-15');
});
});
// Zentrale CSS-Klassenverwaltung
<DatePicker
className={`form-control ${errors ? 'is-invalid' : ''}`}
popperClassName="dropdown-menu"
wrapperClassName="w-100"
/>
// Integrierte Fehleranzeige
{errors[field] && (
<div className="invalid-feedback">
{errors[field].message}
</div>
)}
// Vorher
import DatePicker from 'react-datepicker';
// Nachher (nur Wrapper-Komponente ändern)
import { DatePicker } from '@mui/x-date-pickers';
type CoreProps = Pick<ReactDatePickerProps,
'minDate' | 'maxDate' | 'excludeDates'
>;
interface DateFieldProps extends CoreProps {
// ... eigene Props
}
<DatePicker
dateFormat="yyyy.MM.dd"
showYearDropdown
dropdownMode="select"
{...props}
/>
const useDateFormatter = () => {
const formatDate = (date: Date) =>
new Intl.DateTimeFormat('de-DE').format(date);
return { formatDate };
};
const GenerateField = ({ fieldType, ...props }) => {
switch(fieldType) {
case 'date':
return <DateField {...props} />;
case 'number':
return <NumberField {...props} />;
// ...
}
};
❌ Blindes Prop-Forwarding
// Schlecht: Alle Props werden durchgereicht
<DatePicker {...props} />
✅ Selektives Forwarding
// Gut: Nur bekannte Props erlauben
<DatePicker
minDate={props.minDate}
maxDate={props.maxDate}
/>
Wrapper-Komponenten sind mehr als nur eine Hülle – sie sind strategische Abstraktionsebenen. Durch sie erreichen Sie:
"Gute Wrapper-Komponenten sind wie Übersetzer – sie machen fremde Bibliotheken zur natürlichen Erweiterung Ihres Codebase."
Mit dem gezeigten Muster können Sie jede Drittanbieter-Komponente sicher in Ihre React-Anwendung integrieren – sei es für Formulare, Data Grids oder komplexe Visualisierungen.
©Sergey Emelyanov 2025 | Alle Rechte vorbehalten