fix: CRITICAL ROOT CAUSE - Prevent wizard component recreation on every keystroke
ROOT CAUSE ANALYSIS:
The input focus loss bug was caused by the wizard steps being recreated on
EVERY SINGLE RENDER of UnifiedAddWizard, which happened on EVERY KEYSTROKE.
DETAILED PROBLEM FLOW:
1. User types in name field → handleDataChange called
2. handleDataChange calls setWizardData → UnifiedAddWizard re-renders
3. Line 127: steps={getWizardSteps()} called on every render
4. getWizardSteps() calls InventoryWizardSteps(wizardData, setWizardData)
5. Returns NEW array with NEW component function references:
component: (props) => <InventoryDetailsStep {...props} data={data} onDataChange={setData} />
6. React compares old component ref with new ref, sees they're different
7. React UNMOUNTS old component and MOUNTS new component
8. Input element is DESTROYED and RECREATED → LOSES FOCUS
This happened on EVERY keystroke because:
- wizardData updates on every keystroke
- getWizardSteps() runs on every render
- New component functions created every time
- React sees different function reference = different component type
SOLUTION:
Used useMemo to memoize the wizardSteps array so it's only recreated when
selectedItemType changes, NOT when wizardData changes.
const wizardSteps = useMemo(() => {
// ... generate steps
}, [selectedItemType, handleItemTypeSelect]);
Now the step component functions maintain the same reference across renders,
so React keeps the same component instance mounted, preserving input focus.
IMPACT:
✅ Inputs no longer lose focus while typing
✅ Component state is preserved between keystrokes
✅ No more unmount/remount cycles on every keystroke
✅ Dramatically improved performance (no unnecessary component recreation)
This was the TRUE root cause - the previous fixes helped but didn't solve
the fundamental architectural issue of recreating components on every render.
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useCallback } from 'react';
|
import React, { useState, useCallback, useMemo } from 'react';
|
||||||
import { Sparkles } from 'lucide-react';
|
import { Sparkles } from 'lucide-react';
|
||||||
import { WizardModal, WizardStep } from '../../ui/WizardModal/WizardModal';
|
import { WizardModal, WizardStep } from '../../ui/WizardModal/WizardModal';
|
||||||
import { ItemTypeSelector, ItemType } from './ItemTypeSelector';
|
import { ItemTypeSelector, ItemType } from './ItemTypeSelector';
|
||||||
@@ -57,7 +57,9 @@ export const UnifiedAddWizard: React.FC<UnifiedAddWizardProps> = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Get wizard steps based on selected item type
|
// Get wizard steps based on selected item type
|
||||||
const getWizardSteps = (): WizardStep[] => {
|
// CRITICAL: Memoize the steps to prevent component recreation on every render
|
||||||
|
// Without this, every keystroke causes the component to unmount/remount, losing focus
|
||||||
|
const wizardSteps = useMemo((): WizardStep[] => {
|
||||||
if (!selectedItemType) {
|
if (!selectedItemType) {
|
||||||
// Step 0: Item Type Selection
|
// Step 0: Item Type Selection
|
||||||
return [
|
return [
|
||||||
@@ -95,7 +97,7 @@ export const UnifiedAddWizard: React.FC<UnifiedAddWizardProps> = ({
|
|||||||
default:
|
default:
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
};
|
}, [selectedItemType, handleItemTypeSelect]); // Only recreate when item type changes, NOT when wizardData changes
|
||||||
|
|
||||||
// Get wizard title based on selected item type
|
// Get wizard title based on selected item type
|
||||||
const getWizardTitle = (): string => {
|
const getWizardTitle = (): string => {
|
||||||
@@ -124,7 +126,7 @@ export const UnifiedAddWizard: React.FC<UnifiedAddWizardProps> = ({
|
|||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
onComplete={handleWizardComplete}
|
onComplete={handleWizardComplete}
|
||||||
title={getWizardTitle()}
|
title={getWizardTitle()}
|
||||||
steps={getWizardSteps()}
|
steps={wizardSteps}
|
||||||
icon={<Sparkles className="w-6 h-6" />}
|
icon={<Sparkles className="w-6 h-6" />}
|
||||||
size="xl"
|
size="xl"
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user