
React Counter App
초기화하는 0버튼 만들어주고
onClickButton 이벤트 변경해주기
App.jsx
const onClickButton = (value) => {
if(value){
setCount(count + value);
} else {
setCount(0);
}
};
Mount-탄생, 페이지에 나타남
Update-업데이트, State업데이트,Props업데이트,부모컴포넌트 리렌더
Unmount-죽음,페이지에서 사라짐(제거됨)
useEffect(callback, [deps]);
callback->콜백함수, [deps]->의존성배열
count값 변경될 때마다 확인하는 useEffect 생성해서 콘솔로 확인해보기
App.jsx
import { useState, useEffect } from 'react';
useEffect(() => {
console.log(`count: ${count}` );
}, [count]);
input 추가해서 확인해보기
App.jsx
const [input, setInput] = useState("");
useEffect(() => {
console.log(`count: ${count}`, `input: ${input}`);
}, [count, input]);
//React Counter App밑에 input 표시하기
return (
<div className="App">
<h1>React Counter App</h1>
<section>
<input
value={input}
onChange={(e) => {
setInput(e.target.value);
}}>
</input>
</section>
...
App.jsx
//1. 마운트(처음 렌더링될때만 실행되게 의존성배열을 빈배열로 넣어준다)
useEffect(()=>{
console.log("마운트 되었음");
}, []);
//2. 업데이트(리렌더링될때마다 계속 실행되게 두번째인자 의존성배열생략,
//특정스테이트변수 변화감지하고싶을경우 의존성배열에 감시하고싶은거만 넣어주기)
useEffect(()=>{
console.log("업데이트 되었음");
});
업데이트 되었을 때만 업데이트 표시하기
App.jsx
import { useState, useEffect, useRef } from 'react';
const isMount = useRef(false);
//2. 업데이트
useEffect(()=>{
if(!isMount.current){
isMount.current = true;
return
}
console.log("업데이트 되었음"); //마운트시점이 아닌 경우
});
App.jsx
import './App.css'
import { useState, useEffect, useRef } from 'react';
import Viewer from './components/Viewer';
import Controller from './components/Controller';
import Even from './components/Even';
function App() {
const [count, setCount] = useState(0);
const [input, setInput] = useState("");
//console.log(count);
// useEffect(() => {
// console.log(`count: ${count}, input: ${input}`);
// }, [count, input]);
const isMount = useRef(false);
//1. 마운트(처음 렌더링될때만 실행되게 의존성배열을 빈배열로넣어준다)
useEffect(()=>{
console.log("마운트 되었음");
}, []);
//2. 업데이트(리렌더링될때마다 계속 실행되게 두번째인자 의존성배열생략,
//특정스테이트변수 변화감지하고싶을때에는 의존성배열에 감시하고싶은거만 넣어주기)
useEffect(()=>{
if(!isMount.current){
isMount.current = true;
return
}
console.log("업데이트 되었음");
});
//이벤트핸들러 사용하기
const onClickButton = (value) => {
if(value){
setCount(count + value);
} else {
setCount(0);
}
};
return (
<div className="App">
<h1>React Counter App</h1>
<section>
<input
value={input}
onChange={(e) => {
setInput(e.target.value);
}}>
</input>
</section>
<section>
<Viewer count={count}/>
{count %2 === 0? <Even /> : null}
</section>
<section>
<Controller onClickButton = {onClickButton} />
</section>
</div>
);
}
export default App;
1초마다 깜빡 메세지 출력하기(언마운트되면 깜박이지않게하기)
Even.jsx
import { useEffect } from "react";
const Even = () => {
useEffect(() => {
console.log("이븐 컴포넌트 마운트");
const intervalID = setInterval(()=>{
console.log("깜박");
}, 1000);
return () => { //클린업함수(정리함수)
console.log("이븐 컴포넌트 언마운트");
clearInterval(intervalID); //언마운트되면 깜박하지않게
}
}, [])
return <div>짝수입니다!!!</div>
};
export default Even;
->확장프로그램관리에서 켜져있는지확인하고 세부정보 확인하고 아래항목 켜기

크롬개발자도구 >>클릭하고 Components,Profiler 안보이면

Restore defaults and reload 실행해주면된다.

요구사항 분석
컴포넌트 단위
components 디렉토리만들어서 그 안에 Header.jsx,Editor.jsx,List.jsx 만들기
List.jsx
const List = () => {
return <div>List</div>
};
export default List;
위와 같은 형식으로 만들어주고 App으로 가져오기
App.jsx
import './App.css';
import Header from './components/Header';
import Editor from './components/Editor';
import List from './components/List';
function App() {
return (
<div className="App">
<Header />
<Editor/>
<List/>
</div>
);
}
export default App;
App.jsx에서 className주고 App.css에서 외부스타일링하기
.App {
width: 500px;
margin: 0 auto;
display: flex;
flex-direction: column;
gap: 10px;
}
오늘날짜 표시하는 헤더 만들기
Header.jsx(이모티콘은 윈도우키+.으로 입력하기)
import "./Header.css";
const Header = () => {
return (
<div className="Header">
<h3>오늘은...🕰</h3>
<h1>{new Date().toDateString()}</h1>
</div>
);
};
export default Header;
Header.css
.Header h1 {
color: blueviolet;
}
할일 추가하는 에디터 만들기
Editor.jsx
import "./Editor.css";
const Editor = () => {
return (
<div className="Editor">
<input placeholder="새로운 할일..."/>
<button>추가</button>
</div>
);
};
export default Editor;
Editor.css
.Editor {
display: flex;
gap: 10px;
}
.Editor input {
flex: 1;
padding: 15px;
border: 1px solid rgb(220, 220, 220);
border-radius: 5px;
}
.Editor button {
cursor: pointer;
width: 80px;
border: none;
background-color: blueviolet;
color: white;
border-radius: 5px;
}
할일리스트 보여주는 리스트 만들기
List.jsx
import "./List.css";
const List = () => {
return <div className="List">
<h4>🎈Todo List...🎈</h4>
<input placeholder="검색어를 입력하세요" />
</div>
};
export default List;
List.css
.List {
display: flex;
flex-direction: column;
gap: 20px;
}
.List input {
width: 100%;
border: none;
border-bottom: 1px solid rgb(220,220,220);
padding: 15px 0px;
}
.List input:focus {
outline: none;
border-bottom: 1px solid rgb(153,185,250);
}
할일리스트에 들어가는 할일아이템 만들기
TodoItem.jsx
import "./TodoItem.css"
const TodoItem = () => {
return <div>todoItem</div>;
};
export default TodoItem;
리스트에서 아이템 렌더링해서 보여주기
List.jsx
import "./List.css"
import TodoItem from "./TodoItem";
const List = () => {
return <div className="List">
<h4>🎈Todo List...🎈</h4>
<input placeholder="검색어를 입력하세요" />
<div className="todos_wrapper">
<TodoItem/>
<TodoItem/>
<TodoItem/>
</div>
</div>
};
export default List;
기본형태만들어주기
TodoItem.jsx
import "./TodoItem.css"
const TodoItem = () => {
return <div className="TodoItem"><input type="checkbox" />
<div className="content">할일</div>
<div className="date">날짜</div>
<button>삭제</button>
</div>;
};
export default TodoItem;
TodoItem.css
.TodoItem {
display: flex;
align-items: center;
gap: 20px;
padding-bottom: 20px;
border-bottom: 1px solid rgb(220,220,220);
}
.TodoItem input {
width: 20px;
}
.TodoItem .content {
flex: 1;
}
.TodoItem .date {
color: gray;
font-size: 14px;
}
.TodoItem button {
cursor: pointer;
color: gray;
font-size: 14px;
border: none;
border-radius: 5px;
padding: 5px;
}
List.jsx에서 스타일링하기위해 div에 className="todos_wrapper"주고
List.css에 todos_wrapper 추가해준다.
.List .todos_wrapper {
display: flex;
flex-direction: column;
gap: 20px;
}
todos State 만들기
const [todos, setTodos] = useState([]); ->여러개의 할 일을 관리하기위해 빈배열로 초기화, testData를 useState에 넣어준다.
App.jsx
import './App.css';
import { useState, useRef } from 'react';
import Header from './components/Header';
import Editor from './components/Editor';
import List from './components/List';
const testData = [
{
id:0,
isDone: false,
content: "React 공부하기",
date: new Date().getTime(),
},
{
id:1,
isDone: false,
content: "밥먹기",
date: new Date().getTime(),
},
{
id:2,
isDone: false,
content: "운동하기",
date: new Date().getTime(),
},
];
function App() {
const [todos, setTodos] = useState(testData);
const idRef = useRef(3);
return (
<div className="App">
<Header />
<Editor/>
<List/>
</div>
);
}
export default App;
App컴포넌트에서 testData 제대로 들어갔는지 개발자도구로 확인해보기

추가버튼눌렀을때 새로운 할 일 생성해서 보여주는 함수 onCreate 만들고
Editor에 onCreate props 전달해주기
App.jsx
import './App.css';
import { useState, useRef } from 'react';
import Header from './components/Header';
import Editor from './components/Editor';
import List from './components/List';
const textData = [
{
id:0,
isDone: false,
content: "React 공부하기",
date: new Date().getTime(),
},
{
id:1,
isDone: false,
content: "밥먹기",
date: new Date().getTime(),
},
{
id:2,
isDone: false,
content: "운동하기",
date: new Date().getTime(),
},
];
function App() {
const [todos, setTodos] = useState(textData);
const idRef = useRef(3);
const onCreate = (content) => {
const newTodo = {
id: idRef.current++,
isDone: false,
content: content,
date: new Date().getTime(),
};
setTodos([newTodo,...todos]);
};
return (
<div className="App">
<Header />
<Editor onCreate={onCreate} />
<List/>
</div>
);
}
export default App;
Editor에서 onCreate를 props로 전달받아서 onSubmit 이벤트핸들러 만들어서
onCreate 호출되도록 만들어서 추가버튼 onClick이벤트에 onSubmit 이벤트핸들러 등록하기,
input값 보관하기위한 state 생성하고 변화가생기면 state값을 갱신해줄 onChangeContent 만들어서 OnChange이벤트에 등록하기
Editor.jsx
import "./Editor.css";
import { useState } from "react";
const Editor = ({ onCreate }) => {
const [content,setContent] = useState("");
const onChangeContent = (e) => {
setContent(e.target.value);
};
const onSubmit = () => {
onCreate(content);
}
return (
<div className="Editor">
<input
value={content}
onChange={onChangeContent}
placeholder="새로운 할일..."/>
<button onClick={onSubmit}>추가</button>
</div>
);
};
export default Editor;
할일 추가하면 todo State에 잘 들어가는지 개발자도구로 확인하기

아이디다루기위해서 useRef 만들어준다. useRef 이용해서 아이디값 증가하게한다.
App.jsx
import './App.css';
import { useState, useRef } from 'react';
import Header from './components/Header';
import Editor from './components/Editor';
import List from './components/List';
const testData = [
{
id:0,
isDone: false,
content: "React 공부하기",
date: new Date().getTime(),
},
{
id:1,
isDone: false,
content: "밥먹기",
date: new Date().getTime(),
},
{
id:2,
isDone: false,
content: "운동하기",
date: new Date().getTime(),
},
];
function App() {
const [todos, setTodos] = useState(testData);
const idRef = useRef(3);
const onCreate = (content) => {
const newTodo = {
id: idRef.current++,
isDone: false,
content: content,
date: new Date().getTime(),
};
setTodos([newTodo,...todos]);
};
return (
<div className="App">
<Header />
<Editor onCreate={onCreate} />
<List />
</div>
);
}
export default App;
추가할때 입력이 비어있다면 onCreate호출안하고 추가안되게하고 포커스주기
(포커스주기위해 useRef 사용)
, 추가후 빈칸으로 초기화하기, 추가할때 엔터로 추가되게 하는 onKeyDown추가
Editor.jsx
import "./Editor.css";
import { useState, useRef } from "react";
const Editor = ({ onCreate }) => {
const [content,setContent] = useState("");
const contentRef = useRef();
const onChangeContent = (e) => {
setContent(e.target.value);
};
const onKeyDown = (e) => { //엔터이벤트
if(e.keyCode === 13){
onSubmit();
}
};
const onSubmit = () => {
if(content===""){
contentRef.current.focus(); //포커스주기
return;//비어있다면 추가버튼 눌러도 들어가지않게한다.
}
onCreate(content);
setContent(""); //추가후 초기화
}
return (
<div className="Editor">
<input
ref={contentRef}
value={content}
onKeyDown={onKeyDown}
onChange={onChangeContent}
placeholder="새로운 할일..."/>
<button onClick={onSubmit}>추가</button>
</div>
);
};
export default Editor;
List에 todos props로 전달해주고 map함수이용해서 List 렌더링해서 보여주기
List.jsx
import "./List.css";
import TodoItem from "./TodoItem";
const List = ({ todos }) => {
return (
<div className="List">
<h4>🎈Todo List...🎈</h4>
<input placeholder="검색어를 입력하세요" />
<div className="todos_wrapper">
{todos.map((todo) => {
return <TodoItem {...todo} />
})}
</div>
</div>
);
};
export default List;
List에 todos props 전달되어있고 데이터들어가있는지 개발자도구로 확인할 수 있다.

List에서 던진 props todo 사용해서 화면에 렌더링해준다.
TodoItem.jsx
import "./TodoItem.css"
const TodoItem = ({id, isDone, content, date }) => {
const onChangeCheckBox = () => {
onUpdate(id);
};
const onClickDeleteButton = () => {
onDelete(id);
}
return (
<div className="TodoItem">
<input checked={isDone} type="checkbox" />
<div className="content">{content}</div>
<div className="date">{new Date(date).toLocaleDateString()}</div>
<button>삭제</button>
</div>
);
};
export default TodoItem;