삭제 기능을 추하하기 위해 li안에 버튼 생성
<li key={index}><span>{item}</span> <button>X</button></li>
버튼을 클릭했을 때 해당 todo가 삭제되는 함수를 onDelete로 생성한다
요소를 구분하는 key값은 index와 같으므로 onDelete 함수의 인자로 index값을 넘긴다
<li key={index}><span>{item}</span>
<button onClick={() => onDelete(index)}>X</button></li>
이 때
onClick={() => onDelete(index)}
을onClick={onDelete(index)}
로 작성하면 클릭될 때가 아닌 rendering될 때 실행되므로 주의
onDelete함수는 index를 받아 같은 위치인 요소(cur)을 제외한 배열을 todos로 수정한다.
filter함수는 조건에 맞는 요소들로 새로운 배열을 반환하는 함수로
(현재 요소, 인덱스값, 호출한 배열)을 인자로 갖는다
const onDelete = (index) => {
setTodos((curArray) =>
curArray.filter((_, curi) => curi!==index));
}
실행해보면 잘 삭제되는 것을 확인 할 수 있다.
수정 기능을 추가하기 위해 삭제와 같이 버튼을 생성한다
<li key={index}>
<span>{item}</span>
<button>수정</button>
<button>X</button>
</li>
수정버튼을 클릭하면 해당 span 대신 input박스로 변하고 value에는 해당 내용이 셋팅되게 할 것이다.
그러기 위해서는 li의 모드가 수정 모드인지 아닌지를 저장할 배열변수가 필요하다. 이를 modifyMode라 설정한다. todo가 추가될 때 해당 todo의 모드를 저장할 modifyMode도 false(수정하지 않는다는 의미)값을 하나씩 추가한다
const [modifyMode, setModifyMode] = useState([]);
const onSubmit = (event) => {
....
setModifyMode((curArray) => [false, ...curArray]);
}
수정 버튼을 클릭하면 setModifyMode를 이용하여 같은 index의 modifyMode값만 토글되도록 함수를 작성하였다. 새로운 배열을 반환해야하기 때문에 map을 이용하였다
const onModifyMode = (index) => {
setModifyMode((curArray) =>
curArray.map((cur, curi) => {
if(curi === index)
return !cur;
return cur;
})
)
};
html은 modifyMode[index] 값이 false면 span을 true면 value값이 text인 input을 반환하도록 하였다. onChange 이벤트 없이 value를 설정하면 오류가 발생하므로 text를 수정하여 저장할 onModify함수도 생성하였다. input의 값을 가져와하기 때문에 event를 onModify에 넘겨주었다
{modifyMode[index] ?
<input value={item}
onChange={(event) => onModify(event, index)}>
</input>
: <span>{item}</span>
}
onModify 함수는 index값으로 todos에서 수정할 위치를 찾고 input에 적힌 값으로 수정되어야 하기 때문에 다음과 같이 작성하고 실행 시켜보면 잘 작동하는 것을 확인 할 수 있다.
const onModify = (event, index) => {
setTodos((curArray) =>
curArray.map((cur, curi) => {
if(curi === index)
return event.target.value;
return cur;
})
)
};
전체코드
import {useState} from "react";
function App() {
const [todo, setTodo] = useState("");
const [todos, setTodos] = useState([]);
const [modifyMode, setModifyMode] = useState([]);
const onChange = (event) => setTodo(event.target.value);
const onSubmit = (event) => {
event.preventDefault();
if(todo === ""){
return ;
}
setTodos((curArray) => [todo, ...curArray]);
setModifyMode((curArray) => [false, ...curArray]);
setTodo("");
};
const onDelete = (index) => {
setTodos((curArray) =>
curArray.filter((_, curi) => curi!==index));
};
const onModifyMode = (index) => {
setModifyMode((curArray) =>
curArray.map((cur, curi) => {
if(curi === index)
return !cur;
return cur;
})
)
};
const onModify = (event, index) => {
setTodos((curArray) =>
curArray.map((cur, curi) => {
if(curi === index)
return event.target.value;
return cur;
})
)
};
return (
<div>
<h1>My To Dos ({todos.length})</h1>
<form onSubmit={onSubmit}>
<input
onChange={onChange}
value={todo}
type="text"
placeholder="Write your to do..."
/>
<button>Add To Do</button>
</form>
<hr />
<ul>
{todos.map((item, index) => (
<li key={index}>
{modifyMode[index] ? <input value={item} onChange={(event) => onModify(event, index)}></input> : <span>{item}</span>}
<button onClick={() => onModifyMode(index)}>수정</button>
<button onClick={() => onDelete(index)}>×</button></li>
))}
</ul>
</div>
);
}
export default App;