📌 들어가며
간단한 일정 관리 todolist (투두리스트) 입니다.
할일 추가, 삭제, 체크(할일 다함) 기능이 구현되어 있습니다.
구현하면서 알게된 것들을 정리했습니다.
📌 todolist (투두리스트) 구성
투두리스트의 컴포넌트 구조를 그림으로 그려봤습니다.
App 안에 입력창, 할 일 목록들을 넣었습니다.
JSX 형식으로 표현하면 아래와 같습니다.
[App.js]
<div className="App">
<TodoItem/> //할일 목록 및 할 일 (ul - li)
</div>
📌 구조 작성해보기
1. input 입력창에서 값을 받아서 업데이트(change)
2. 입력값(value) 받기
3. 등록 버튼 클릭해서 값 저장
4. 입력값을 배열로 저장 (리스트 저장)
5. input 입력값을 어딘가에 뿌려줘 (리스트를 보여줘)
6. 뿌려진 목록에서 원하는 값을 선택 (checkbox) 해서 삭제
📌 입력값 받아서 업데이트 (change)
[App.js]
function App() {
const [inputValue, setInputValue] = useState(''); // 입력값, 입력값 set
const [inputList, setInputList] = useState([]); // 입력값 리스트, 입력값 리스트 set
// 입력값을 setInputValue 으로 set
const changeTodoInput = (e) => {
setInputValue (e.target.value);
}
return (
<div className="App">
<div>
<input type="input" value={inputValue} onChange={changeTodoInput}/>
</div>
</div>
);
}
📌 일정 추가하기 (input value 값 저장)
입력창(Input)에 입력한 값을 useState로 관리하기
[App.js]
function App() {
const [inputValue, setInputValue] = useState('');
const [inputList, setInputList] = useState([]);
const changeTodoInput = (e) => {
setInputValue (e.target.value);
}
// 할일 추가
const addTodo = () => {
setInputList([...inputList, inputValue]); // ...으로 기존값 가져오기, 현재 입력값
setInputValue(''); // 입력값 초기화 ''
}
return (
<div className="App">
<div>
<input type="input" value={inputValue} onChange={changeTodoInput}/>
<button type="button" onClick={addTodo}>등록</button>
</div>
</div>
);
}
1. onChange 이벤트 : 입력창에 친 값들 추적해서 setInputValue에 저장합니다.
📌 inputList의 값을 화면에 뿌려주기 (input 입력값을 어딘가에 뿌려줘, 리스트를 보여줘)
App.js
function App() {
// ...
return (
<div className="App">
<div>
<input type="input" value={inputValue} onChange={changeTodoInput}/>
<button type="button" onClick={addTodo}>등록</button>
</div>
<ul className="content-list">
{inputList.map((item, i) => {
return (
<li>
<input type="checkbox"/>
<span>{item}</span>
<button type="button">삭제</button>
</li>
)
})}
</ul>
</div>
);
}
1. map을 활용하여 inputList 에 있는 item 값들을 화면에 뿌려준다.
📌 삭제하기 (목록에 있는 값 삭제)
function App() {
// 내가 선택한 item의 index
const deleteTodo = (index) => {
// 내가 삭제하고자 하는 item의 index와 inputList에 있는 index(i) 값을 비교
// ex) 내가 삭제하고자 하는 item은 3번째라면 index 값은 4,
// inputList에 있는 index(i) 값은 첫번째줄부터 비교를 시작하기때문에 0부터 시작
// 4와 0 비교 / 4와 1 비교 / 4와 2 비교 / 4와 3 비교 ....
// return 에서 true 만 남기는 원리
// filter 는 true 일 때 값을 item(값)을 반납한다.(return 해준다.)
setInputList(inputList.filter((item, i) => {
return index !== i
// 아래 코드는 위 코드 한줄과 동일
// if (index === i) {
// return false
// } else{
// return true
// }
}))
}
const onClickDelete = (i) => {
deleteTodo(i)
}
return (
<div className="App">
<div>
<input type="input" value={inputValue} onChange={changeTodoInput}/>
<button type="button" onClick={addTodo}>등록</button>
</div>
<ul className="content-list">
{inputList.map((item, i) => {
return (
<li>
<input type="checkbox"/>
<span>{item}</span>
// onClick은 기본적으로 이벤트를 넘겨주는데 onClickDelete에서 필요한 것은 선택한 item의 index 이기 때문에
// 인라인으로 선언해서 명시적으로 i(index)값을 넣어서 호출한다.
<button type="button" onClick={(e)=>{onClickDelete(i)}}>삭제</button>
</li>
)
})}
</ul>
</div>
);
}
📌 TodoItem의 컴포넌트화
* 컴포넌트로 빼는 이유 :
- 모든 컴포넌트는 재활용성을 향상시키기 위해서
-(내가 쓰고자 하는 이유) 체크박스 선택시, css 수정을 위해서 독립적으로 랜더링해줄 수 있는 State 값이 필요
어떤 현상이 발생 하는지?
-> App 컴포넌트 안에 체크박스 value를 선언하면 checkbox 클릭시, 모든 item 이 선택되는 이슈가 발생함
TodoItem.js
import { useState } from 'react';
// TodoItem === 컴포넌트
function TodoItem ({item, i, deleteTodo}) {
const [isValidCheck, setIsValidCheck] = useState(false);
const changeCheck = () => {
setIsValidCheck(!isValidCheck); // 기존 값에 반대
}
const onClickDelete = () => {
deleteTodo(i)
}
return (
<li>
<input type="checkbox" value={isValidCheck} onChange={changeCheck}/>
<span style={{ textDecoration: isValidCheck?'line-through':'none',color:isValidCheck?'red':'#000' }}>{item}</span>
<button type="button" onClick={onClickDelete}>삭제</button>
</li>
)
}
export default TodoItem;
TodoItem을 컴포넌트로 뺐으니 App.js 도 수정
import { useState } from 'react';
// 컴포넌트 추가
import TodoItem from './TodoItem';
function App() {
const [inputValue, setInputValue] = useState('');
const [inputList, setInputList] = useState([]);
const changeTodoInput = (e) => {
setInputValue (e.target.value);
}
const addTodo = () => {
setInputList([...inputList, inputValue]);
setInputValue('');
}
const deleteTodo = (index) => {
console.log(index)
setInputList(inputList.filter((item, i) => {
return index !== i
// if (index === i) {
// return false
// }else{
// return true
// }
}))
}
return (
<div className="App">
<div>
<input type="input" value={inputValue} onChange={changeTodoInput}/>
<button type="button" onClick={addTodo}>등록</button>
</div>
<ul className="content-list">
{inputList.map((item, i) => {
return (
// <TodoItem/> -> 컴포넌트 사용법
// key 는 유일한 값을 넣어준다.
// item={item} -> property={inputList에 있는 각각의 item}
// property는 받아주는 값의 이름이다. (컴포넌트에서 가져올 때 쓰는 이름)
// deleteTodo 는 함수를 가져옴
<TodoItem key={i} item={item} i={i} deleteTodo={deleteTodo}/>
)
})}
</ul>
</div>
);
}
export default App;
🔮 [ 완성 코드 ] 🔮
[App.js]
import { useState } from 'react';
import TodoItem from './TodoItem';
// 컴포넌트 안하고 내부에서 사용할 때
// TodoItem === 컴포넌트
// function TodoItem ({item, i, deleteTodo}) {
// const [isValidCheck, setIsValidCheck] = useState(false);
// const changeCheck = () => {
// setIsValidCheck(!isValidCheck); // 기존 값에 반대
// }
// const onClickDelete = () => {
// deleteTodo(i)
// }
// return (
// <li>
// <input type="checkbox" value={isValidCheck} onChange={changeCheck}/>
// <span style={{ textDecoration: isValidCheck?'line-through':'none',color:isValidCheck?'red':'#000' }}>{item}</span>
// <button type="button" onClick={onClickDelete}>삭제</button>
// </li>
// )
// }
function App() {
const [inputValue, setInputValue] = useState('');
const [inputList, setInputList] = useState([]);
const changeTodoInput = (e) => {
setInputValue (e.target.value);
}
const addTodo = () => {
setInputList([...inputList, inputValue]);
setInputValue('');
}
const deleteTodo = (index) => {
console.log(index)
setInputList(inputList.filter((item, i) => {
return index !== i
// if (index === i) {
// return false
// }else{
// return true
// }
}))
}
// const onClickDelete = (i) => {
// deleteTodo(i)
// }
return (
<div className="App">
<div>
<input type="input" value={inputValue} onChange={changeTodoInput}/>
<button type="button" onClick={addTodo}>등록</button>
</div>
<ul className="content-list">
{inputList.map((item, i) => {
return (
<TodoItem key={i} item={item} i={i} deleteTodo={deleteTodo}/>
)
// return (
// <li>
// <input type="checkbox"/>
// <span>{item}</span>
// <button type="button" onClick={(e)=>{onClickDelete(i)}}>삭제</button>
// </li>
// )
})}
</ul>
</div>
);
}
export default App;
🔮 [ 완성 코드 ] 🔮
[TodoItem.js]
import { useEffect, useState } from 'react';
// TodoItem === 컴포넌트
function TodoItem ({item, i, deleteTodo}) {
const [isValidCheck, setIsValidCheck] = useState(false);
const changeCheck = () => {
setIsValidCheck(!isValidCheck); // 기존 값에 반대
}
const onClickDelete = () => {
deleteTodo(i)
}
return (
<li>
<input type="checkbox" value={isValidCheck} onChange={changeCheck}/>
<span style={{ textDecoration: isValidCheck?'line-through':'none',color:isValidCheck?'red':'#000' }}>{item}</span>
<button type="button" onClick={onClickDelete}>삭제</button>
</li>
)
}
export default TodoItem;
'React' 카테고리의 다른 글
[React] 간단한 tab(탭) 만들기 (feat. checkbox 추가) (0) | 2024.05.29 |
---|---|
[React] 노마드 수업 1-state, setState 등 소스 (0) | 2022.07.23 |
[React] 노마드 수업 1- 소스 (0) | 2021.08.20 |
[React] 노마드 수업 1 (0) | 2021.08.20 |
[React] 설치 및 시작하기 - 노마드 수업 정리 (0) | 2021.08.20 |