구성하기 App.js
function App() {
return (
<div className="App">
<Header />
<Editor />
<List />
</div>
);
}
export default App;
Header, Editor, List 컴포넌트로 만들기
Header.js
function Header() {
return (
<div>
<h3>TODOLIST 🗓️</h3>
<h2>{new Date().toDateString()}</h2>
</div>
)
}
export default Header;
Editor.js
const Editor = () => {
return (
<div>
<input placeholder="할일 추가" />
<button>추가</button>
</div>
)
}
export default Editor
List.js
function List() {
return (
<div className="List">
<h4>Todo List😀</h4>
<input placeholder="검색어를 입력하세요" />
<div className='todos_wrapper'>
<TodoItem />
<TodoItem />
<TodoItem />
</div>
</div>
)
}
export default List
List.js에 들어갈 컴포넌트 TodoItem.js 생성
const TodoItem = () => {
return (
<div>
<input type="checkbox" />
<div>Todo...</div>
<div>Date</div>
<button>삭제</button>
</div>
)
}
export default TodoItem;
App.js
import './App.css';
import Header from './component/Header';
import Editor from './component/Editor';
import List from './component/List';
import { useState } from 'react';
const tmpData = [
{
id:0,
isDone: false,
content: "React 공부하기",
data: new Date().getTime(),
},
{
id:1,
isDone: false,
content: "꿀맛같은 휴식",
data: new Date().getTime(),
},
{
id:2,
isDone: false,
content: "친구화의 수다",
data: new Date().getTime(),
},
]
function App() {
const [todos, setTodos] = useState(tmpData)
const onCreate = (content) => {
const newItem = {
id :0,
isDone :false,
content: content,
date : new Date().getTime()
}
setTodos([newItem, ...todos])
==> { }, { }, { } 이렇게 하나씩 풀어서 그 앞에 새로운 값을 넣어주고 다시 하나의 배열로
만든다. [ { }, { }, { }, { } ]
}
return (
<div className="App">
<Header />
<Editor onCreate={onCreate} />
<List />
</div>
);
}
export default App;
Editor.js
const Editor = ({onCreate}) => {
const [content, setContent] = useState("");
return (
<div className="Editor">
<input onChange={(e) => {setContent(e.target.value)}} placeholder="할일 추가" />
<button onClick={()=> {onCreate(content)}}>추가</button>
</div>
)
}
export default Editor
현재 추가한 항목들의 id가 다 0으로 나오는 것 해결해야 한다. ⇒ useRef ( )사용
App.js
import { useState, useRef } from 'react';
function App() {
const [todos, setTodos] = useState(tmpData)
const idRef = useRef(3)
const onCreate = (content) => {
const newItem = {
id : idRef.current++,
isDone :false,
content: content,
date : new Date().getTime()
}
setTodos([newItem, ...todos])
}
return (
<div className="App">
<Header />
<Editor onCreate={onCreate} />
<List />
</div>
);
}
데이터를 추가하면,
내용을 작성하지 않고, 추가를 누르면 빈 내용이 추가되는 것을 방지하기 위해 Editor.js에 코드를 추가해준다.
Editor.js
const Editor = ({onCreate}) => {
const [content, setContent] = useState("");
const contentRef = useRef();
return (
<div className="Editor">
<input onChange={(e) => {setContent(e.target.value)}} placeholder="할일 추가" />
<button onClick={()=> {
if(content == "") {
return;
}
onCreate(content)}
}>추가</button>
</div>
)
}
export default Editor
+ 추가로 input 박스에 focus를 맞춰준다.
return (
<div className="Editor">
<input ref={contentRef} onChange={(e) => {setContent(e.target.value)}} placeholder="할일 추가" />
<button onClick={()=> {
if(content == "") {
contentRef.current.focus();
return;
}
onCreate(content)}
}>추가</button>
</div>
)
++ 추가를 누르면 input 박스에 해당 글이 남지 않도록 지워준다.
return (
<div className="Editor">
<input value={content} ref={contentRef} onChange={(e) => {setContent(e.target.value)}} placeholder="할일 추가" />
<button onClick={()=> {
if(content == "") {
contentRef.current.focus();
return;
}
onCreate(content)
setContent("")
}}> 추가</button>
</div>
)
App.js에 있는 데이터들을 List목록에 띄워주어야 한다.
const tmpData = [
{
id:0,
isDone: false,
content: "React 공부하기",
data: new Date().getTime(),
},
{
id:1,
isDone: false,
content: "꿀맛같은 휴식",
data: new Date().getTime(),
},
{
id:2,
isDone: false,
content: "친구화의 수다",
data: new Date().getTime(),
},
]
const [todos, setTodos] = useState(tmpData)
현재 todos에 담겨있음
<List todos={todos}/>
props로 넘겨준다.
List.js
function List({todos}) {
return (
<div className="List">
<h4>Todo List😀</h4>
<input placeholder="검색어를 입력하세요" />
<div className='todos_wrapper'>
{
todos.map( todo =>
<TodoItem {...todo} />
)
}
</div>
</div>
)
}
export default List
TodoItem.js
const TodoItem = ({id, isDone, content, date}) => {
return (
<div className='TodoItem'>
<input type="checkbox" checked={isDone} />
<div className='content'>{content}</div>
<div className='date'>{new Date(date).toLocaleDateString()}</div>
<button>삭제</button>
</div>
)
}
export default TodoItem;
검색 기능 추가
List.js
function List({todos}) {
const [search, setSearch] = useState("")
const getFilterdData = () => {
if(search == "") {
return todos;
}
return todos.filter((todo) =>
todo.content.includes(search) // includs() 함수 : todo.content와 search가 같으면 true반환, 다르면 false반환
)
}
const filteredTodos = getFilterdData();
return (
<div className="List">
<h4>Todo List😀</h4>
<input placeholder="검색어를 입력하세요" onChange={(e)=>{setSearch(e.target.value)}}/>
<div className='todos_wrapper'>
{
filteredTodos.map(todo =>
<TodoItem {...todo} />
)
}
</div>
</div>
)
}
export default List
대소문자 구분 없이 검색하도록
⇒ todo.content와 search의 값을 비교하기 전에 전부 대문자 처리 OR 소문자 처리하도록 해준다.
return todos.filter((todo) =>
todo.content.toLowerCase().includes(search.toLowerCase())
// includs() 함수 : todo.content와 search가 같으면 true반환, 다르면 false반환
)
check 상태 바꾸기
App.js
const onUpdate = targetId => {
setTodos(todos.map(todo=>{
if(todo.id == targetId) {
return {
...todo,
isDone: !todo.isDone // true면 false로, false면 true로
}
}
return todo
}))
}
위 코드를 삼항연산자로 줄이기
const onUpdate = targetId => {
setTodos(todos.map(todo => todo.id == targetId? {...todo, isDone: !todo.isDone} : todo ))
}
List로 넘겨주기
<List todos={todos} onUpdate={onUpdate} />
List.js
넘겨준 값 받기
function List({todos, onUpdate}) {
...
TodoItem으로 넘겨준다.
{
filteredTodos.map(todo =>
<TodoItem {...todo} onUpdate={onUpdate} />
)
}
TodoItem.js
넘겨준 값 받기
const TodoItem = ({id, isDone, content, date, onUpdate}) => {
return (
<div className='TodoItem'>
<input type="checkbox" checked={isDone} onChange={()=>onUpdate(id)} />
<div className='content'>{content}</div>
<div className='date'>{new Date(date).toLocaleDateString()}</div>
<button>삭제</button>
</div>
)
}
export default TodoItem;
체크가 잘되고,
isDone 값이 true로 잘 바뀐다.
삭제하기
App.js
const onDelete = targetId => {
setTodos(todos.filter(todo => todo.id !== targetId));
}
<List todos={todos} onUpdate={onUpdate} onDelete={onDelete}/>
filter 함수를 사용하여 조건을 만족하지 않는 모든 요소를 유지하고, 삭제하려는 요소는 제거한다.
이 방법은 기존의 배열을 변경하지 않고 새로운 배열을 반환하여 요소를 삭제한다.
List.js
function List({todos, onUpdate, onDelete}) {
...
<TodoItem {...todo} onUpdate={onUpdate} onDelete={onDelete} />
TodoItem.js
const TodoItem = ({id, isDone, content, date, onUpdate, onDelete}) => {
...
<button onClick={()=>{onDelete(id)}}>삭제</button>
'React' 카테고리의 다른 글
[React] 리액트-스프링부트 연동하기 (0) | 2024.03.22 |
---|---|
[React] 로컬 스토리지 (0) | 2024.03.22 |
[React] Context Api와 redux (0) | 2024.03.22 |
[React] axios (0) | 2024.03.22 |
[React] 리액트 부트스트랩 적용 (0) | 2024.03.21 |