fix(modal-repeater-table): 품목 추가 시 UI 즉시 반영되지 않는 버그 수정

- value 상수를 localValue useState로 변경하여 내부 상태 관리
- useEffect로 외부 값(formData, propValue) 변경 시 동기화
- handleChange에서 setLocalValue 호출하여 즉각적인 UI 업데이트
- RepeaterTable, ItemSelectionModal 등 모든 참조를 localValue로 변경
This commit is contained in:
SeongHyun Kim
2025-12-04 19:05:43 +09:00
parent 0e4ecef336
commit c1400081c6
4 changed files with 173 additions and 17 deletions

View File

@@ -193,7 +193,18 @@ export function ModalRepeaterTableComponent({
// ✅ value는 formData[columnName] 우선, 없으면 prop 사용
const columnName = component?.columnName;
const value = (columnName && formData?.[columnName]) || componentConfig?.value || propValue || [];
const externalValue = (columnName && formData?.[columnName]) || componentConfig?.value || propValue || [];
// 🆕 내부 상태로 데이터 관리 (즉시 UI 반영을 위해)
const [localValue, setLocalValue] = useState<any[]>(externalValue);
// 🆕 외부 값(formData, propValue) 변경 시 내부 상태 동기화
useEffect(() => {
// 외부 값이 변경되었고, 내부 값과 다른 경우에만 동기화
if (JSON.stringify(externalValue) !== JSON.stringify(localValue)) {
setLocalValue(externalValue);
}
}, [externalValue]);
// ✅ onChange 래퍼 (기존 onChange 콜백 + onFormDataChange 호출 + 납기일 일괄 적용)
const handleChange = (newData: any[]) => {
@@ -249,6 +260,9 @@ export function ModalRepeaterTableComponent({
}
}
// 🆕 내부 상태 즉시 업데이트 (UI 즉시 반영) - 일괄 적용된 데이터로 업데이트
setLocalValue(processedData);
// 기존 onChange 콜백 호출 (호환성)
const externalOnChange = componentConfig?.onChange || propOnChange;
if (externalOnChange) {
@@ -321,7 +335,7 @@ export function ModalRepeaterTableComponent({
const handleSaveRequest = async (event: Event) => {
const componentKey = columnName || component?.id || "modal_repeater_data";
if (value.length === 0) {
if (localValue.length === 0) {
console.warn("⚠️ [ModalRepeaterTable] 저장할 데이터 없음");
return;
}
@@ -332,7 +346,7 @@ export function ModalRepeaterTableComponent({
.filter(col => col.mapping?.type === "source" && col.mapping?.sourceField)
.map(col => col.field);
const filteredData = value.map((item: any) => {
const filteredData = localValue.map((item: any) => {
const filtered: Record<string, any> = {};
Object.keys(item).forEach((key) => {
@@ -389,16 +403,16 @@ export function ModalRepeaterTableComponent({
return () => {
window.removeEventListener("beforeFormSave", handleSaveRequest as EventListener);
};
}, [value, columnName, component?.id, onFormDataChange, targetTable]);
}, [localValue, columnName, component?.id, onFormDataChange, targetTable]);
const { calculateRow, calculateAll } = useCalculation(calculationRules);
// 초기 데이터에 계산 필드 적용
useEffect(() => {
if (value.length > 0 && calculationRules.length > 0) {
const calculated = calculateAll(value);
if (localValue.length > 0 && calculationRules.length > 0) {
const calculated = calculateAll(localValue);
// 값이 실제로 변경된 경우만 업데이트
if (JSON.stringify(calculated) !== JSON.stringify(value)) {
if (JSON.stringify(calculated) !== JSON.stringify(localValue)) {
handleChange(calculated);
}
}
@@ -506,7 +520,7 @@ export function ModalRepeaterTableComponent({
const calculatedItems = calculateAll(mappedItems);
// 기존 데이터에 추가
const newData = [...value, ...calculatedItems];
const newData = [...localValue, ...calculatedItems];
console.log("✅ 최종 데이터:", newData.length, "개 항목");
// ✅ 통합 onChange 호출 (formData 반영 포함)
@@ -518,7 +532,7 @@ export function ModalRepeaterTableComponent({
const calculatedRow = calculateRow(newRow);
// 데이터 업데이트
const newData = [...value];
const newData = [...localValue];
newData[index] = calculatedRow;
// ✅ 통합 onChange 호출 (formData 반영 포함)
@@ -526,7 +540,7 @@ export function ModalRepeaterTableComponent({
};
const handleRowDelete = (index: number) => {
const newData = value.filter((_, i) => i !== index);
const newData = localValue.filter((_, i) => i !== index);
// ✅ 통합 onChange 호출 (formData 반영 포함)
handleChange(newData);
@@ -543,7 +557,7 @@ export function ModalRepeaterTableComponent({
{/* 추가 버튼 */}
<div className="flex justify-between items-center">
<div className="text-sm text-muted-foreground">
{value.length > 0 && `${value.length}개 항목`}
{localValue.length > 0 && `${localValue.length}개 항목`}
</div>
<Button
onClick={() => setModalOpen(true)}
@@ -557,7 +571,7 @@ export function ModalRepeaterTableComponent({
{/* Repeater 테이블 */}
<RepeaterTable
columns={columns}
data={value}
data={localValue}
onDataChange={handleChange}
onRowChange={handleRowChange}
onRowDelete={handleRowDelete}
@@ -573,7 +587,7 @@ export function ModalRepeaterTableComponent({
multiSelect={multiSelect}
filterCondition={filterCondition}
modalTitle={modalTitle}
alreadySelected={value}
alreadySelected={localValue}
uniqueField={uniqueField}
onSelect={handleAddItems}
columnLabels={columnLabels}