방을 추가하고, 삭제 할 수 있는 기능으로써 특정 방을 삭제하면 해당 방의 데이터만 삭제되고 나머지 값들은 자동으로 앞당겨 오도록 구현했다.
(목적)
삭제 버튼 클릭 시 해당 행의 방만 삭제 되도록 구현
(예를 들어 방 1 ~ 3까지 있는 상태에서 방 2를 삭제 할 경우 방 2의 값은 삭제되고, 방 3의 값은 방 2로 앞당겨 져야 한다.)
(과정)
- 방 하나를 구성하고 있는 객체는 form이다.
- 삭제 버튼을 클릭 시 해당 행의 고유값(i)를 삭제 함수(deleteRoom)의 인자(파라미터)로 넘겨준다.
- 해당 고유값을 지니고 있는 key 값을 삭제한다. (delete form[`room${i}`];
- 삭제된 key 값 다음으로 있는 key 값들의 value를 하나씩 앞당긴다.
(앞당겨 오는 과정에서는 https://developer-syubrofo.tistory.com/105를 참고했다.
1. React hook 중 useState를 사용하여 form 객체를 생성한다.
const [form, setForm] = useState({
count: 1,
room1: "",
});
- count : 방의 갯수 (방 1이 기본값이기 때문에 초기값에 1을 넣어줬다.)
- room1 : 방 1 정보 (방 1이 기본값이기 때문에 초기값에 넣어줬다.)
2. JSX에서는 배열 함수 중 map을 사용하여 방을 출력한다.
<>
{form.count > 0 &&
[...Array(form.count)].map((item, i) => {
return (
<div key={i + 1}>
방 {i + 1}
<input
type="text"
placeholder={i + 1}
value={form[`room${i + 1}`]}
name={`room${i + 1}`}
onChange={(e) => {
setForm({ ...form, [e.target.name]: e.target.value });
}}
/>
<button
onClick={() => {
deleteRoom(i + 1);
}}
>
삭제
</button>
</div>
);
})}
<div onClick={addRoom}>
<p>+ 방 추가</p>
</div>
<br />
<br />방 갯수 : {form.count}
</>
- form.count > 0 : 꼭 필요한 부분은 아니지만, 예외 처리를 위해 설정했다.
- [...Array(form.count)].map(() => {}) : form.count는 Array가 아니라 Number 타입이기 때문에 form.count만큼 배열을 생성해서 .map을 돌려준다.
- 그 외에는 방을 구성하는 text, input, button(삭제 버튼)과 방 추가하는 div 정도가 있다.
3. 방 추가 기능 구현
<div onClick={addRoom}>
<p>+ 방 추가</p>
</div>
방 추가 div 클릭 시(onClick)
const addRoom = () => {
const number = form.count + 1;
setForm({
...form,
count: number,
[`room${number}`]: "",
});
};
addRoom 함수가 호출되면서 count를 1 증가 시키고, 추가된 방의 정보를 담는 key 값을 추가 해준다.
4. 방 삭제 기능 구현
<button
onClick={() => {
deleteRoom(i + 1);
}}
>
삭제
</button>
삭제 버튼을 클릭 시(onClick) deleteRoom 함수를 호출하게 되는 데
이때 인자로 i + 1을 넘겨준다. 왜냐하면 특정 방을 삭제하는 것이기 때문에 고유값을 넘겨준다.
const deleteRoom = (i) => {
if (form.count === 1) {
alert("방 1은 필수사항 입니다.");
return;
}
const newForm = { ...form };
for (let n = i; n <= newForm.count; n++) {
if (n === i) {
delete newForm[`room${n}`];
} else {
Object.defineProperty(
newForm,
"room" + (n - 1),
Object.getOwnPropertyDescriptor(newForm, "room" + n)
);
delete newForm[`room${n}`];
}
}
setForm({ ...newForm, count: form.count - 1 });
};
- 방 1은 필수사항이기 때문에 if문을 사용해서 처리 해주었다.
- const newForm = {...form}; : form 객체를 전개 연산자를 사용하여 복사 해주었다.
- 삭제하는 방 다음에 있는 방들의 값들을 하나씩 앞당겨야 하기 때문에 for문 조건에 n의 기본값을 i로 설정 해주었다.
- if문은 삭제된 방을 의미하고, else문은 삭제된 방 다음에 있는 방들을 의미한다.
🤔 delete 객체[key 값] : 객체에서 해당 key 값을 찾아 삭제하는 역할
🤔 Object.defineProperty(obj, prop, descriptor);
→ obj : 속성을 정의하고자 하는 객체
→ prop : 새로 정의하거나 수정하고자 하는 속성의 이름
→ descriptot : 새로 정의하거나 수정하려는 속성에 대해 기술하는 객체
> 객체에 직접 새로운 속성을 정의하거나 이미 존재하는 객체를 수정한 뒤 그 객체를 반환한다.
🤔 Object.getOwnPropertyDescriptor(obj, prop);
→ obj : 속성을 찾을 대상 객체
→ prop : 설명이 검색될 속성명 (새로운 객체 이름)
> 속성값에 해당하는 속성 설명자를 반환한다.
(출력)
(전체 코드)
import { useState } from "react";
const Test = () => {
const [form, setForm] = useState({
count: 1,
room1: "",
});
const addRoom = () => {
const number = form.count + 1;
if (number >= 10) {
alert("개인실을 추가 할 수 없습니다.");
return;
}
setForm({
...form,
count: number,
[`room${number}`]: "",
});
};
const deleteRoom = (i) => {
if (form.count === 1) {
alert("방 1은 필수사항 입니다.");
return;
}
const newForm = { ...form };
for (let n = i; n <= newForm.count; n++) {
if (n === i) {
delete newForm[`room${n}`];
} else {
Object.defineProperty(
newForm,
"room" + (n - 1),
Object.getOwnPropertyDescriptor(newForm, "room" + n)
);
delete newForm[`room${n}`];
}
}
setForm({ ...newForm, count: form.count - 1 });
};
return (
<>
{form.count > 0 &&
[...Array(form.count)].map((item, i) => {
return (
<div key={i + 1}>
방 {i + 1}
<input
type="text"
placeholder={i + 1}
value={form[`room${i + 1}`]}
name={`room${i + 1}`}
onChange={(e) => {
setForm({ ...form, [e.target.name]: e.target.value });
}}
/>
<button
onClick={() => {
deleteRoom(i + 1);
}}
>
삭제
</button>
</div>
);
})}
<div onClick={addRoom}>
<p>+ 방 추가</p>
</div>
<br />
<br />방 갯수 : {form.count}
</>
);
};
export default Test;
'더 알아보기 > 기능' 카테고리의 다른 글
[React, Next.js] react-beautiful-dnd를 사용하여 드래그로 순서 변경하기 (0) | 2022.06.28 |
---|---|
[JS] 객체 👉 배열 / 배열 👉 객체 (0) | 2022.05.27 |
[CSS] animation, @keyframes를 사용한 화면 전화 CSS (0) | 2022.05.13 |
[Next.js] Chart.js 라이브러리로 구현한 도넛 차트의 tooltip이 말썽을 부린다. (0) | 2022.05.12 |
ToolTip (2) - Bootstrap/react-tooltip (0) | 2022.05.11 |
댓글