반응형
개요
입력폼 map 돌리는걸 생각 못하고 일단은 input값을 추가할때마다 span 태그로 감싸진 리스트에 추가하게끔 했다.
하지만 이 기능은 추가 버튼을 눌러야만 추가가 되다보니 입력만하고 넘어가는 경우가 생겼다.
그래서 UX적으로 여러개의 input값을 받을 수 있게끔 변환 작업을 했다.
1. input 입력값 인터페이스 타입 지정
export interface NewOptionDetailType {
id: string;
name: string;
option_id: string;
price: string | number;
}
2. input 입력값 전역상태 선언
menuOptionDetail: {
id: '',
name: '',
option_id: '',
price: '',
},
menuOptionDetailList: [],
setMenuOptionDetail: (item: NewOptionDetailType) => set({ menuOptionDetail: item }),
setMenuOptionDetailList: (item: NewOptionDetailType[]) => set(state => ({ ...state, menuOptionDetailList: item })),
3. onChange 이벤트
number type이었던 price쪽이 0이 안지워지는 이슈가 있어서 타입을 string으로 변환해서 숫자만 받게끔 적용했다.
const changeMenuOptionItemHandler = (e: React.ChangeEvent<HTMLInputElement>, index: number) => {
const inputItemsCopy: NewOptionDetailType[] = [...menuOptionDetailList];
const { value, name } = e.target;
if (name === 'detailName') inputItemsCopy[index].name = value;
else if (name === 'detailPrice') {
const newValue = value.replace(/[^0-9e]/gi, '');
if (newValue.includes('e')) return;
inputItemsCopy[index].price = newValue;
}
setMenuOptionDetailList(inputItemsCopy);
};
4. 추가 기능
price 쪽이 숫자값만 받다보니 0이 안지워지는 이슈가 있어서 string으로 전환해서 추가할때 빈값으로 초기화 시켜줬다.
const addOptionDetailInputHandler = () => {
setMenuOptionDetailList([...menuOptionDetailList, { ...menuOptionDetail, price: '' }]);
};
5. 삭제 기능
삭제된 해당 index를 찾아서 리스트에서 제거하게 했다.
// 옵션 detail 삭제
const removeOptionDetailhandler = async (optionDetailIndex: number) => {
const removedItemList = menuOptionDetailList.filter((_, index) => index !== optionDetailIndex);
setMenuOptionDetailList(removedItemList);
};
6. 화면에 map() 함수를 이용해 뿌려주기
key 값은 index보다 id값으로 들어가는게 좋은데, 저장하기 전까진 해당 db로 넘기기전엔 id값이 없기에 index로 들어갔다.
<div className={styles['option-detail-wrap']}>
<div className={styles['top']}>
<p className={styles['input-name']}>옵션 추가</p>
<button className={styles['plus-btn']} onClick={addOptionDetailInputHandler}>
<span className={styles['img']}>
<PlusButton width={14} height={14} />
</span>
<span className={styles['txt']}>항목 추가하기</span>
</button>
</div>
<div className={styles['option-three-wrap']}>
{menuOptionDetailList.map((item, index) => (
<div key={index} className={styles['input-wrap']}>
<input
name="detailName"
type="text"
className={styles['input']}
onChange={e => changeMenuOptionItemHandler(e, index)}
value={item.name}
placeholder="옵션 내용"
/>
<input
name="detailPrice"
type="text"
className={styles['input']}
onChange={e => changeMenuOptionItemHandler(e, index)}
value={item.price}
placeholder="옵션 가격"
/>
<button onClick={() => removeOptionDetailhandler(index)}>삭제</button>
</div>
))}
</div>
</div>
+ 7. 초기값은 입력폼이 기본 하나는 있기를 원한다면
기본 배열에 빈값을 하나 넣어놔도 되지만, 본인은 처음 생성은 1개의 입력폼,
만약 저장시 다 삭제하고 저장하면 그 다음 수정할 때 입력폼이 없어야하기 때문에 menuOptionIndex라는 수정인지 등록인지를 구분하여 최초접근시에만 하나를 추가하는 이벤트를 추가했다.
useEffect(() => {
if (menuOptionIndex === -1) addOptionDetailInputHandler();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
결과화면
반응형
'TIL' 카테고리의 다른 글
[TIL][24.01.30] drag and drop 클래스 에러 해결 (0) | 2024.01.31 |
---|---|
[TIL][24.01.29] React, className 복수 classname 적용(clsx 라이브러리 사용) (1) | 2024.01.30 |
[TIL][24.01.25] Project - 전역 상태 비동기 업데이트 (1) | 2024.01.26 |
[TIL][24.01.24] Project - react 직접 drag and drop 구현 (0) | 2024.01.25 |
[TIL][24.01.23] project - magic pos QA (1) | 2024.01.23 |