MAISON CODE .
/ UX · B2B · React · Performance

Matrix-Bestellung: Entwicklung leistungsstarker B2B-Grids

Ein tiefer Einblick in den Aufbau leistungsstarker B2B-Matrix-Bestellraster für Tausende von Varianten. Beherrschung der Reaktionsvirtualisierung, Zustandsverwaltung und API-Batching.

AB
Alex B.
Matrix-Bestellung: Entwicklung leistungsstarker B2B-Grids

In der schnelllebigen Welt des B2C-E-Commerce verläuft die Benutzerreise linear: Durchsuchen, Auswählen, In den Warenkorb legen. Aber B2B ist eine ganz andere Sache. Ein Großhandelskäufer eines Modehändlers möchte nicht fünfzig Mal für fünfzig verschiedene Hemdgrößen auf „In den Warenkorb“ klicken. Sie wollen Effizienz. Sie wollen Geschwindigkeit. Sie wollen eine Matrix.

Bei Maison Code Paris haben wir gesehen, wie B2B-Portale unter ihrem eigenen Gewicht zusammenbrachen. Wir haben „Unternehmens“-Lösungen gesehen, die zum Rendern einer Produktseite vier Sekunden benötigen, weil sie naiverweise 2.000 Eingaben für einen einzelnen Schraubentyp rendern. Das ist inakzeptabel. In der Großhandelswirtschaft nervt Reibung nicht nur den Benutzer; es zerstört die Schleife der wiederkehrenden Einnahmen.

Dieser Leitfaden ist ein tiefer technischer Einblick in den Aufbau des „Excel des E-Commerce“: Das Matrix Ordering Grid.

Warum Maison Code darüber spricht

Bei Maison Code Paris fungieren wir als das architektonische Gewissen unserer Kunden. Wir übernehmen oft „moderne“ Stacks, die ohne grundlegendes Verständnis für Skalierung gebaut wurden.

Wir diskutieren dieses Thema, weil es einen kritischen Wendepunkt in der technischen Reife darstellt. Die korrekte Implementierung unterscheidet ein fragiles MVP von einer widerstandsfähigen Plattform auf Unternehmensniveau.

Warum Maison Code die Matrixreihenfolge bespricht

Wir bauen umfangreiche B2B-Plattformen für Luxushäuser und Industriegiganten. Der Unterschied zwischen einem Tool, das sich wie ein modernes SaaS anfühlt, und einem Tool, das sich wie ein veraltetes ERP anfühlt, ist oft das Matrix Grid. Wenn ein Käufer in Sekundenschnelle und ohne Verzögerung Mengen für 500 Varianten über die Tastaturnavigation eingeben kann, fühlt er sich professionell. Sie fühlen sich respektiert.

Wir diskutieren dies, weil es an der Schnittstelle zwischen schweren technischen Einschränkungen (DOM-Beschränkungen, API-Beschränkungen) und hochwertiger Benutzererfahrung liegt. Für die Lösung ist mehr als nur eine UI-Bibliothek erforderlich; Es erfordert ein grundlegendes Verständnis darüber, wie der Browser rendert und wie der Status durch eine Anwendung fließt.

Das Skalierbarkeitsproblem: O(n)-Rendering

Betrachten Sie ein einfaches B2B-Produkt: ein T-Shirt.

  • Farben: 10
  • Größen: 8
  • Gesamtvarianten: 80 Eingaben.

Mit React können Sie 80 Eingaben rendern, ohne ins Schwitzen zu geraten.

Betrachten Sie nun einen Industriebolzen.

  • Längen: 50
  • Gewindesteigung: 20
  • Materialien: 10
  • Gesamtvarianten: 10.000 Eingaben.

Wenn Sie versuchen, 10.000 „“-Elemente gleichzeitig in das DOM zu rendern, friert Ihre Anwendung ein. Der Flaschenhals ist nicht die Ausführung von JavaScript; Es handelt sich um die Phasen Layout und Paint der Browser-Engine. Jedes Mal, wenn der Benutzer ein Zeichen in ein Feld eingibt und Ihre Statusverwaltung naiv ist, versucht React möglicherweise, den gesamten Baum abzugleichen.

Die Kosten für das erneute Rendern

Wenn Sie ein einzelnes „useState“-Objekt für das gesamte Formular verwenden:

„tsx const [formState, setFormState] = useState({}); „

Jeder Tastendruck löst ein erneutes Rendern der übergeordneten Komponente aus, wodurch dann 10.000 untergeordnete Komponenten neu gerendert werden. Selbst mit „React.memo“ führt allein die Prop-Differenzierung für 10.000 Komponenten zu einer spürbaren Eingabeverzögerung. Bei einem professionellen Tool ist der Input-Lag fatal.

Phase 1: Virtualisierung (Die DOM-Lösung)

Der erste Schritt zur Leistung besteht darin, anzuerkennen, dass der Benutzer nicht 10.000 Eingaben gleichzeitig betrachten kann. Ein typischer Monitor zeigt vielleicht 50 Datenzeilen an.

Virtualisierung (oder „Windowing“) ist die Technik, bei der nur die DOM-Knoten gerendert werden, die derzeit im Ansichtsfenster sichtbar sind. Während der Benutzer scrollt, zerstören wir die Knoten, die den oberen Bildschirmrand verlassen, und erstellen neue, die den unteren Rand betreten. Der Browser geht davon aus, dass er ein 5.000 Pixel großes Element scrollt, aber das DOM enthält nur 50 „div“s.

Für diese Implementierung empfehlen wir TanStack Virtual (headless) oder react-window.

Implementierungsmuster

So strukturieren wir ein virtualisiertes Raster für eine B2B-Matrix. Wir behandeln das Gitter als Koordinatensystem (Zeile, Spalte).

„tsx import { useVirtualizer } from ‘@tanstack/react-virtual’; import { useRef } aus ‘react’;

// Die „Single Source of Truth“ für die Matrixdaten // Idealerweise typischerweise abgeflacht oder strukturiert als Map<VariantID, Quantity> type MatrixData = Record<string, number>;

export const VirtualizedMatrix = ({ Zeilen, Spalten, Daten }: MatrixProps) => { const parentRef = useRef(null);

const rowVirtualizer = useVirtualizer({ count: rows.length, getScrollElement: () => parentRef.current, geschätzte Größe: () => 50, // 50 Pixel Zeilenhöhe overscan: 5, // 5 zusätzliche Zeilen rendern für reibungsloses Scrollen });

zurück ( <div ref={parentRef} Stil={{ Höhe: 600px, Überlauf: ‘auto’, }} > <div Stil={{ Höhe: €{rowVirtualizer.getTotalSize()}px, Breite: ‘100%’, Position: ‘relativ’, }} > {rowVirtualizer.getVirtualItems().map((virtualRow) => { const rowData = rows[virtualRow.index]; zurück ( <div key={virtualRow.key} Stil={{ Position: ‘absolut’, oben: 0, links: 0, Breite: ‘100%’, Höhe: €{virtualRow.size}px, transform: translateY(€{virtualRow.start}px), Anzeige: ‘flex’, }} > {/* Spalten (Zellen) hier rendern */} {columns.map((col) => ( <MatrixEingabe key={col.id} variantId={getVariantId(rowData, col)} /> ))} ); })} ); }; „

Wichtige Erkenntnisse: Virtualisierung reduziert die anfängliche Ladezeit für große Datenmengen von 3,5 s auf 0,2 s. Für Kataloge mit mehr als 500 Varianten ist es nicht verhandelbar.

Phase 2: Zustandsverwaltung (Die Speicherlösung)

Virtualisierung löst das Rendering-Problem, aber wir haben immer noch ein Statusproblem. Wenn wir den Status von 10.000 Eingaben im React State halten, erfordert die Aktualisierung einer Eingabe eine sorgfältige Optimierung, um zu vermeiden, dass eine baumweite Aktualisierung ausgelöst wird.

Der Signalansatz

Bei Maison Code bevorzugen wir Signale (über „@preact/signals-react“ oder rein granulare Abonnenten) oder Unkontrollierte Komponenten für Matrixgitter.

Wenn wir unkontrollierte Komponenten verwenden, umgehen wir den Renderzyklus von React für die Tippaktion vollständig.

  1. Lesen: defaultValue={data.get(id)}
  2. Schreiben: onChange={(e) => data.set(id, e.target.value)} (Direkte Mutation oder Ref-Aktualisierung)
  3. Senden: Aus der Referenz/Karte lesen.

Allerdings benötigen wir oft Berechneten Zustand (z. B. „Gesamtmenge: 150“). Damit sind wir wieder im Bereich der Reaktivität.

Der beste moderne Ansatz ist Zustand mit transienten Updates.

„tsx // store.ts import { create } from ‘zustand’;

Schnittstelle MatrixStore { Mengen: Record<string, number>; setQuantity: (id: string, qty: number) => void; // Berechnete Werte, die in Komponenten oder Selektoren innerhalb von Komponenten abgeleitet wurden }

export const useMatrixStore = create((set) => ({ Mengen: {}, setQuantity: (id, qty) => set((state) => ({ Mengen: { …state.quantities, [id]: qty } })), }));

// MatrixInput.tsx // Diese Komponente abonniert NUR ihren spezifischen Statusabschnitt const MatrixInput = ({ variantId }) => { const qty = useMatrixStore((state) => state.quantities[variantId] || 0); const setQuantity = useMatrixStore((state) => state.setQuantity);

zurück (
    <Eingabe 
        value={qty} 
        onChange={(e) => setQuantity(variantId, parseInt(e.target.value))} 
    />
);

} „

Dadurch wird sichergestellt, dass bei der Eingabe einer Zelle nur diese bestimmte Zelle (und möglicherweise der Zähler „Gesamt“) und nicht das gesamte Raster neu gerendert wird.

Phase 3: Mikrointeraktionen und UX

Geschwindigkeit ist technisch, aber auch wahrnehmungsabhängig. Ein B2B-Käufer erwartet, dass sich das Tool wie eine Tabellenkalkulation verhält.

Tastaturnavigation

Eine mauslastige Schnittstelle ist für die Masseneingabe zu langsam. Wir müssen Pfeiltastennavigation implementieren.

  • Eingabetaste: Nach unten verschieben (Tabellenkalkulationsstandard).
  • Tabulatortaste: Nach rechts bewegen.
  • Pfeiltasten: In die entsprechende Richtung bewegen.

Dies erfordert eine programmatische Steuerung des Fokus. Da wir virtualisieren, ist die Eingabe, auf die Sie sich konzentrieren möchten, möglicherweise noch nicht im DOM vorhanden. Das ist der schwierige Teil. Sie müssen den Virtualizer zum Index scrollen, bevor Sie versuchen, den Fokus zu setzen.

Sofortiges Inventar-Feedback

Benutzer sollten nicht auf „In den Warenkorb“ warten, um zu erfahren, dass eine Variante nicht vorrätig ist. Wir rufen Bestandsdaten in einem einfachen Format vorab ab:

„json { „Variante_1“: 50, „Variante_2“: 0, „Variante_3“: 1200 } „

Wir ordnen dies einem visuellen Zustand zu.

  • Ausgegraut: Ausverkauft (0).
  • Gelbe Warnung: Geringer Lagerbestand (Benutzer hat 50 eingegeben, Lagerbestand ist 40).
  • Roter Rand: Ungültige Eingabe.

Diese Validierung muss synchron auf der Clientseite erfolgen.

Phase 4: API-Nutzlast und Stapelverarbeitung

Der Benutzer klickt auf „Zur Bestellung hinzufügen“. Sie haben 150 einzigartige Varianten ausgewählt. Die meisten REST-APIs (einschließlich der Standard-Cart-API von Shopify) sind nicht dafür ausgelegt, 150 Werbebuchungen effizient in einer einzigen HTTP-POST-Anfrage aufzunehmen. Es kann zu einer Zeitüberschreitung kommen oder die Nutzlastgrenzen werden überschritten.

Strategie: Die Batched Promise Queue

Wir blockieren niemals die Benutzeroberfläche. Wir zeigen einen Fortschrittsbalken an („Elemente hinzufügen… 40 %“).

„Typoskript const BATCH_SIZE = 50;

asynchrone Funktion addToCartRecursive(items: Item[]) { if (items.length === 0) return;

const chunk = items.slice(0, BATCH_SIZE);
const verbleibend = items.slice(BATCH_SIZE);

// Optimistisches UI-Update hier

versuche es mit {
    Warten Sie auf api.cart.add(chunk);
    updateProgress((total - verbleibende Länge) / total);
    return addToCartRecursive(remaining); // Nächste Charge
} Catch (Fehler) {
    handlePartialFailure(chunk, error);
}

} „


Strategie: Die Warenkorb-Transformation (Shopify)

Für Shopify Plus-Händler nutzen wir Cart Transform Functions oder Bundles. Wir können einen einzelnen übergeordneten Artikel („The Matrix Bundle“) zum Warenkorb hinzufügen und ihn beim Bezahlen von der Backend-Logik in Einzelartikel erweitern lassen. Dadurch bleiben die Warenkorb-Interaktionen blitzschnell, während die Backend-Logik für die Auftragsabwicklung erhalten bleibt. Weitere Informationen hierzu finden Sie in unserem Leitfaden zur Checkout-Erweiterbarkeit.

##Mobil: Der Pivot Ein 50x20-Raster ist auf Mobilgeräten nicht möglich. Versuchen Sie nicht, es durch Verkleinern der Zellen reaktionsfähig zu machen. Es ist unbrauchbar.

Auf Mobilgeräten schwenken wir die Benutzeroberfläche. Anstelle von „Zeilen = Größen“ und „Spalten = Farben“ zeigen wir einfach das Primäre Attribut (z. B. Farbe) als Liste an.

  • Benutzer tippt auf „Rot“.
  • Ein Akkordeon dehnt sich aus (oder ein unteres Blatt öffnet sich).
  • Der Benutzer sieht eine Liste mit Größen für „Rot“.
  • Der Benutzer gibt Mengen ein.
  • Der Benutzer minimiert „Rot“ und tippt auf „Blau“.

Dieser „Drill-Down“-Ansatz respektiert die kleine Bildschirmfläche, während die Datenhierarchie intakt bleibt.

Leistungsbenchmarks

Als wir einen großen Kunden von einem Standard-React-Formular auf eine virtualisierte Zustandsmatrix migrierten, beobachteten wir Folgendes:

| Metrisch | Legacy Grid (Standardreaktion) | Maison-Code-Matrix (virtualisiert) | Verbesserung | | :

Beauftragen Sie unsere Architekten.