오늘도 코딩하나
[moneybook]_day4 본문
지금까지 짠 코드에 대한 찜찜한 부분들이 많이 있었고,그에 따라 GPT에게 코드 리뷰를 맡겨보았다.
[코드 리뷰 및 개선 사항]
1. 상태 업데이트 시 콜백 함수 사용
const handleUpdate = (id, key, event) => {
let newItem = event.target.innerText;
if(key === 'price1' || key === 'price2') {
if(newItem.trim() === '') {
newItem = 0;
event.target.innerText = '0';
}
}
// 수정 전 소스
const newData = tempData.map((item) =>
item.id === id ? { ...item, [key]: newItem } : item
)
setTempData(newData);
// 수정 후 소스
setTempData(prevData => prevData.map((item) =>
item.id === id ? { ...item, [key]: newItem } : item
))
}
2. 컴포넌트 내 반복 로직 최소화
// 수정 전 소스
{tempData.map((item,i) => (
<tr key={i}>
<td><input type="checkbox" checked={checkedItems.includes(item.id)} onChange={() => handleCheck(item.id)} disabled={disabledItems.includes(item.id)} /></td>
<Input ref={el => inputRefs.current[i * 7 + 0] = el} onBlur={(e) => handleUpdate(item.id, 'date', e)} onKeyDown={(e) => handleKeyDown(e, (i+1)*7+0)} onClick={(e)=>setInitial(e, item)} onKeyUp={(e)=>setInitial(e, item)}>{item.date}</Input>
<Input ref={el => inputRefs.current[i * 7 + 1] = el} onBlur={(e) => handleUpdate(item.id, 'group1', e)} onKeyDown={(e) => handleKeyDown(e, (i+1)*7+1)} onClick={(e)=>setInitial(e, item)} onKeyUp={(e)=>setInitial(e, item)}>{item.group1}</Input>
<Input ref={el => inputRefs.current[i * 7 + 2] = el} onBlur={(e) => handleUpdate(item.id, 'group2', e)} onKeyDown={(e) => handleKeyDown(e, (i+1)*7+2)} onClick={(e)=>setInitial(e, item)} onKeyUp={(e)=>setInitial(e, item)}>{item.group2}</Input>
<Input ref={el => inputRefs.current[i * 7 + 3] = el} onBlur={(e) => handleUpdate(item.id, 'price1', e)} onKeyDown={(e) => handleKeyDown(e, (i+1)*7+3)} onClick={(e)=>setInitial(e, item)} onKeyUp={(e)=>setInitial(e, item)}>{!isNaN(item.price1) ? Number(item.price1).toLocaleString('ko-KR') : item.price1}</Input>
<Input ref={el => inputRefs.current[i * 7 + 4] = el} onBlur={(e) => handleUpdate(item.id, 'price2', e)} onKeyDown={(e) => handleKeyDown(e, (i+1)*7+4)} onClick={(e)=>setInitial(e, item)} onKeyUp={(e)=>setInitial(e, item)}>{!isNaN(item.price2) ? Number(item.price2).toLocaleString('ko-KR') : item.price2}</Input>
<Input ref={el => inputRefs.current[i * 7 + 5] = el} onBlur={(e) => handleUpdate(item.id, 'payment', e)} onKeyDown={(e) => handleKeyDown(e, (i+1)*7+5)} onClick={(e)=>setInitial(e, item)} onKeyUp={(e)=>setInitial(e, item)}>{item.payment}</Input>
<Input ref={el => inputRefs.current[i * 7 + 6] = el} onBlur={(e) => handleUpdate(item.id, 'remark', e)} onKeyDown={(e) => handleKeyDown(e, (i+1)*7+6)} onClick={(e)=>setInitial(e, item)} onKeyUp={(e)=>setInitial(e, item)}>{item.remark}</Input>
</tr>
))}
// 수정 후 소스
const columns = ['date', 'group1', 'group2', 'price1', 'price2', 'payment', 'remark'];
...
{tempData.map((item,i) => (
<tr key={i}>
<td><input type="checkbox" checked={checkedItems.includes(item.id)} onChange={() => handleCheck(item.id)} disabled={item.disabled} /></td>
{columns.map((col, idx) => (
<Input
key={col}
ref={el => inputRefs.current[i * 7 + idx] = el}
onBlur={(e) => handleUpdate(item.id, col, e)}
onKeyDown={(e) => handleUpdate(e, (i + 1) * 7 + idx, e)}
onClick={(e) => setInitial(e, item)}
onKeyUp={(e) => setInitial(e, item)}>
{col.includes('price') && !isNaN(item[col]) ? Number(item[col]).toLocaleString('ko-KR') : item[col]}
</Input>
))}
</tr>
))}
소스코드의 중복 방지를 위해 styled-components를 활용한 Input 컴포넌트를 재사용했다.
하지만 Input 컴포넌트를 사용하는 부분에서 onBlur, onKeyDown 등 반복 코드가 많았고, GPT는 이 점을 지적했다.
그래서 columns 배열을 이용하여 반복을 줄였다.
3. 상태 관리의 단순화
// 수정 전 소스
let [disabledItems, setDisabledItems] = useState([]);
...
setDisabledItems(disabledItems.filter(itemId => itemId !== item.id));
// 수정 후 소스
const [tempData, setTempData] = useState(
payList.map(item => { ...item, isDisabled: false })
);
...
setTempData([...tempData, { id: tempData.length, isDisabled: true }]);
체크박스 선택 불가한 항목들에 대한 id를 disabledItems에 저장하여 활용하는 방안을 택했었는데,
tempData에 isDisabled 필드를 추가하는 방안으로 변경했다.
4. 유틸리티 함수 분리와 모듈화
export const selectText = (e) => {
const range = document.createRange();
const selection = window.getSelection();
range.selectNodeContents(e.target);
selection.removeAllRanges();
selection.addRange(range);
}
App.js 파일에 포함되어 있던 selectText 함수를 별도의 파일(./util/selectText.js)로 만들어서 재사용 가능하게 관리하는 방향으로 변경했다.
다른 컴포넌트나 파일에서 중복 없이 쉽게 사용할 수 있게 되었다.
5. Redux 상태 관리의 비파괴적 업데이트
let payList = createSlice({
name : 'payList',
initialState,
reducers : {
updatePayList(state, action) {
// 수정 전 소스
return action.payload;
// 수정 후 소스
return [ ...state, ...action.payload ];
}
}
})
payList를 복제한 tempData를 수정 후 updatePayList 함수를 호출하여 완전히 payList를 덮어쓰게 했다.
하지만 보통 Redux에서는 피과적인 업데이트가 권장됨에 따라 상태를 복사하여 업데이트하는 방식으로 개선했다.
'React > Daily' 카테고리의 다른 글
[moneybook]_day6 (0) | 2024.09.02 |
---|---|
[moneybook]_day5 (0) | 2024.08.30 |
[moneybook]_day3 (0) | 2024.08.24 |
[moneybook]_day2 (0) | 2024.08.24 |
[moneybook]_day1 (0) | 2024.08.22 |