react로 간단한 todo를 만들어보자.
todos(할일목록들)와 input이 사용자의 행동에 따라 변화하기 때문에 이를 관리하기 위해 state를 사용해야 한다.
먼저 전체 코드는 아래와 같다.
import React, { useState } from 'react'
import "./style.css"
function generateId (){
return Math.floor(Math.random()*100)
}
function Todo() {
const [todos, setTodos] = useState([])
const [input, setInput] = useState('')
const handleSubmit = () => {
setTodos(todos => todos.concat({
text:input,//whatever the user typed in goes to the text
id: generateId()
})
)
setInput('')//clear the input when a new todo has been added
}
const removeTodo = (id) => {
setTodos((todos) => todos.filter((item) => item.id !== id))
}
return (
<div>
<div className='container'>
<input type='text'
value={input} onChange={(e) => setInput(e.target.value)}
placeholder='new todo'/>
<button onClick={handleSubmit}>submit</button>
<ul className='todos-list'>
{
todos.map(({text,id}) => {
return(
<li key={id} className='todo'>
<span>{text}</span>
<button className='close' onClick={() => removeTodo(id)}>X</button>
</li>)
})
}
</ul>
</div>
</div>
)
}
export default Todo
아래의 코드를 보자.
<div className='container'>
<input
type='text'
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder='new todo'/>
<button onClick={handleSubmit}>submit</button>
</div>
input은 유저가 입력한 값을 받아들이는 역할을 하므로, controlled 인풋으로 만들어야 한다. 그래서 value 속성에 input state를 연결하고, onChange 이벤트 핸들러를 사용해 입력된 값을 state에 반영하도록 해준다. onChange 핸들러는 유저가 인풋에 어떤걸 치면 state를 업데이트 해주는 역할을 한다.
버튼을 누르면 handleSubmit 함수가 호출되는데, 이 함수는 새로운 todo를 todos 배열에 추가하고, 입력 필드를 초기화 해준다.
const handleSubmit = () => {
setTodos(todos => todos.concat({
text: input,
id: generateId()
}));
setInput('');
};
여기서는 concat 메서드를 사용해 기존 배열을 변경하지 않고, 새 todo를 추가한 새로운 배열을 반환한다. 이때, text는 유저가 입력한 값이 되고, id는 고유한 아이디가 된다.
generateId()는 위에 쓰여있는 함수를 불러준다.
function generateId (){
return Math.floor(Math.random()*100)
}
각 todo 항목에는 x(삭제)버튼을 만들어 주었고, 이 버튼을 클릭하면 removeTodo 함수가 호출된다. 이 함수는 클릭된 버튼의 id를 기준으로 todos 배열에서 해당 항목을 필터링하여 삭제한다.
<ul className='todos-list'>
{
todos.map(({text,id}) => {
return(
<li key={id} className='todo'>
<span>{text}</span>
<button className='close' onClick={() => removeTodo(id)}>X</button>
</li>)
})
}
</ul>
const removeTodo = (id) => {
setTodos((todos) => todos.filter((item) => item.id !== id))
}
이렇게 하면 특정 항목만 삭제되고, 나머지 항목들은 그대로 유지되게 된다.
