2.3 TodoListItem과 TodoList 만들기
$ yarn create react-app todo-app
$ cd todo-app
$ yarn add sass classnames react-icons
▶ react-icons 리스트와 사용법: https://react-icons.github.io/react-icons/
prettier은 코드를 작성할 때 코드 스타일을 깔끔하게 정리해준다.
.prerttierrc 파일을 최상위 디렉터리에 생성한다.
//.prettierrc
{
“singleQuote“: true,
“semi“: true,
“useTabs“: false,
“tabWidth“: 2,
“trailingComma“: “all“,
“printWidth“: 80
}
index.css는 프로젝트 전체 스타일에 대한 코드가 작성되어 있다.
//index.css
body {
margin: 0;
padding: 0;
background: #e9ecef;
}
// App.js
import React from 'react';
const App = () => {
return <div>Todo App을 만들자!</div>;
};
export default App;
위의 과정을 거치면 리액트 개발 서버를 구동했을 때, 화면처럼 나타난다.
이 4개의 컴포넌트들은 src > components 디렉터리를 생성한 후 저장한다.
컴포넌트를 components 디렉터리 안에 저장하는 이유는 기능, 구조상 필요하기 때문이 아니라 단지 관습 때문이다.
src > components 디렉터리 밑에 TodoTemplate.js와 TodoTemplate.scss 파일을 생성한다.
그리고 js 파일을 다음과 같이 작성한다.
// TodoTemplate.js
import React from ‘react‘;
import ‘./TodoTemplate.scss‘;
const TodoTemplate = ({ children }) => {
return (
<div className=“TodoTemplate“>
<div className=“app-title“>일정 관리</div>
<div className=“content“>{children}</div>
</div>
);
};
export default TodoTemplate;
위에서 만든 컴포넌트를 App.js에 불러와서 렌더링한다.
// App.js
import React from 'react';
import TodoTemplate from './components/TodoTemplate';
const App = () => {
return <TodoTemplate>Todo App을 만들자!</TodoTemplate>;
};
export default App;
컴포넌트를 작성하는 과정에서 상단에 import를 넣지 않고 바로 컴포넌트를 사용하려고 하면
Vs Code 에디터에서 자동 완성 기능이 일어난다.
하지만 TodoTemplate.js 컴포넌트가 Vs Code에서 다른 탭으로 열리지 않았다면 자동 완성이 작동하지 않을 것이다.
닫혀있는 파일에도 자동 완성이 제대로 작동하려면 jsconfig.json 파일을 생성한다.
// jsconfig.json
{
"compilerOptions": {
"target": "es6"
}
}
<사진2개: 실행화면>
파일을 생성 후에 Ctrl + Space를 누르면 위의 자동 완성 박스가 나타난다.
Enter을 누르면 코드가 자동 완성된다.
<사진 수정>
🎨 웹 페이지의 스타일링 하기: TodoTemplate
이제 TodoTemplate.scss를 작성하여 웹 페이지를 스타일링한다.
// TodoTemplate.scss
.TodoTemplate {
width: 512px;
// width가 주어진 상태에서 좌우 중앙 정렬
margin-left: auto;
margin-right: auto;
margin-top: 6rem;
border-radius: 4px;
overflow: hidden;
.app-title {
background: #22b8cf;
color: white;
height: 4rem;
font-size: 1.5rem;
display: flex;
align-items: center;
justify-content: center;
}
.content {
background: white;
}
}
scss를 적용하면 다음과 같이 스타일이 적용된다.
❓ display 속성에 사용되는 flex
레이아웃을 구성할 때 가장 많이 사용되는 속성이다.
flex에 대해서 더 자세히 알고 싶다면 Flexbox Froggy 사이트를 추천한다. flex 속성을 사용하여 개구리의 위치를 설정하고 옮기는 게임으로 flex를 사용하여 레이아웃 설정과 정렬 등을 공부할 수 있다.
▶ Flexbox Froggy: https://flexboxfroggy.com/#ko
▶ Flexbox로 만들 수 있는 10가지 레이아웃: https://d2.naver.com/helloworld/8540176
# flexbox의 장점을 한 마디로 표현하면 '복잡한 계산 없이 요소의 크기와 순서를 유연하게 배치할 수 있다'라고 할 수 있다. 정렬, 방향, 순서, 크기 등을 유연하게 조절할 수 있기 때문에 별도의 분기 처리를 줄일 수 있고, CSS만으로 다양한 레이아웃을 구현할 수 있다. - 출처: Naver D2
이제 입력창(TodoInsert)를 만들려고 한다.
src > components 디렉터리에 TodoInsert.js 파일과 TodoInsert.scss 파일을 생성한다.
// TodoInsert.js
import React from 'react';
import { MdAdd } from 'react-icons/md';
import './TodoInsert.scss';
const TodoInsert = () => {
return (
<form className="TodoInsert">
<input placeholder="할 일을 입력하세요" />
<button type="submit">
<MdAdd />
</button>
</form>
);
};
export default TodoInsert;
이때, react-icons 라이브러리를 통해 아이콘을 사용하였다.
▶ react-icon 페이지: https://react-icons.netlify.com/#/icons/md
react-icons의 페이지를 들어가면 수많은 아이콘과 이름이 함께 나타나있다.
여기서 사용하고 싶은 아이콘을 고른 후, import 구문을 사용하여 아이콘을 불러온다.
import { MdAdd } from 'react-icons/md';
import를 통해 불러온 아이콘을 컴포넌트처럼 사용한다.
<button type="submit">
<MdAdd />
</button>
이제 작성한 컴포넌트(TodoInsert)를 App.js에 불러와 렌더링한다.
// App.js
import React from 'react';
import TodoTemplate from './components/TodoTemplate';
import TodoInsert from './components/TodoInsert';
const App = () => {
return (
<TodoTemplate>
<TodoInsert />
</TodoTemplate>
);
};
export default App;
🎨 웹 페이지 스타일링 하기: TodoInsert
이제 이 컴포넌트를 TodoInsert.scss 파일로 스타일링한다.
//TodoInsert.scss
.TodoInsert {
display: flex;
background: #495057;
input {
// 기본 스타일 초기화
background: none;
outline: none;
border: none;
padding: 0.5rem;
font-size: 1.125rem;
line-height: 1.5;
color: white;
&::placeholder {
color: #dee2e6;
}
// 버튼을 제외한 영역을 모두 차지하기
flex: 1;
}
button {
// 기본 스타일 초기화
background: none;
outline: none;
border: none;
background: #868e96;
color: white;
padding-left: 1rem;
padding-right: 1rem;
font-size: 1.5rem;
display: flex;
align-items: center;
cursor: pointer;
transition: 0.1s background ease-in;
&:hover {
background: #adb5bd;
}
}
}
1. 컴포넌트 생성
(1) TodoListItem 컴포넌트
이제 일정 관리 항목이 보일 TodoListItem과 TodoList 컴포넌트를 생성할 것이다.
src > components 디렉터리 밑에 TodoListItem.js와 TodoListItem.scss 파일을 생성한다.
// TodoListItem.js
import React from ‘react‘;
import {
MdCheckBoxOutlineBlank,
MdCheckBox,
MdRemoveCircleOutline,
} from ‘react-icons/md‘;
import ‘./TodoListItem.scss‘;
const TodoListItem = () => {
return (
<div className=“TodoListItem“>
<div className=“checkbox“>
<MdCheckBoxOutlineBlank />
<div className=“text“>할 일</div>
</div>
<div className=“remove“>
<MdRemoveCircleOutline />
</div>
</div>
);
};
export default TodoListItem;
(2) TodoList 컴포넌트
src > components 디렉터리 밑에 TodoList.js와 TodoList.scss 파일을 생성한다.
// TodoList.js
import React from ‘react‘;
import TodoListItem from ‘./TodoListItem‘;
import ‘./TodoList.scss‘;
const TodoList = () => {
return (
<div className=“TodoList“>
<TodoListItem />
<TodoListItem />
<TodoListItem />
</div>
);
};
export default TodoList;
App.js 에서 TodoList 컴포넌트를 렌더링한다.
// App.js
import React from 'react';
import TodoTemplate from './components/TodoTemplate';
import TodoInsert from './components/TodoInsert';
import TodoList from './components/TodoList';
const App = () => {
return (
<TodoTemplate>
<TodoInsert />
<TodoList />
</TodoTemplate>
);
};
export default App;
🎨 웹 페이지 스타일링 하기: TodoList, TodoListItem
TodoList, TodoListItem 컴포넌트를 scss 파일을 사용하여 스타일링한다.
// TodoListItem.scss
.TodoList {
min-height: 320px;
max-height: 513px;
overflow-y: auto;
}
// TodoList.scss
.TodoListItem {
padding: 1rem;
display: flex;
align-items: center; // 세로 중앙 정렬
&:nth-child(even) {
background: #f8f9fa;
}
.checkbox {
cursor: pointer;
flex: 1; // 차지할 수 있는 영역 모두 차지
display: flex;
align-items: center; // 세로 중앙 정렬
svg {
// 아이콘
font-size: 1.5rem;
}
.text {
margin-left: 0.5rem;
flex: 1; // 차지할 수 있는 영역 모두 차지
}
// 체크되었을 때 보여 줄 스타일
&.checked {
svg {
color: #22b8cf;
}
.text {
color: #adb5bd;
text-decoration: line-through;
}
}
}
.remove {
display: flex;
align-items: center;
font-size: 1.5rem;
color: #ff6b6b;
cursor: pointer;
&:hover {
color: #ff8787;
}
}
// 엘리먼트 사이사이에 테두리를 넣어 줌
& + & {
border-top: 1px solid #dee2e6;
}
}
todos 상태(state)를 사용하여 일정 항목에 대한 상태들을 App에서 관리한다.
App에서 useState를 사용하여 todos 상태를 정의하고 todos를 TodoList의 props로 전달한다.
todos 배열 안에 들어 있는 객체에는 각 항목의 고유값(id), 내용(text), 완료 여부(checked)가 들어있다.
// App.js
import React, { useState } from ‘react‘;
import TodoTemplate from ‘./components/TodoTemplate‘;
import TodoInsert from ‘./components/TodoInsert‘;
import TodoList from ‘./components/TodoList‘;
const App = () => {
const [todos, setTodos] = useState([
{ //useState로 todos 상태를 정의한다.
id: 1,
text: ‘리액트의 기초 알아보기‘,
checked: true,
},
{
id: 2,
text: ‘컴포넌트 스타일링해 보기‘,
checked: true,
},
{
id: 3,
text: ‘일정 관리 앱 만들어 보기‘,
checked: false,
},
]);
return ( // todos를 props로 넘긴다.
<TodoTemplate>
<TodoInsert />
<TodoList todos={todos} />
</TodoTemplate>
);
};
export default App;
TodoList 컴포넌트에서 todos를 받아온 후, 배열 내장 함수 map을 사용하여 TodoListItem으로 변환하여 렌더링한다.
함수 map을 사용하여 컴포넌트를 변환할 때는 key props를 전달해주어야 한다.
// TodoList.js
import React from 'react';
import TodoListItem from './TodoListItem';
import './TodoList.scss';
const TodoList = ({ todos }) => {
return (
<div className="TodoList">
{todos.map(todo => (
<TodoListItem todo={todo} key={todo.id} />
))}
</div>
);
};
export default TodoList;
💡 배열 내장 함수 : map
배열 안의 각 원소들을 변환할 때 새로운 배열을 만들어 리턴하는 함수이다.
const array = [1, 2, 3, 4];
const result = [];
array.forEach(n => {
result.push(n * n);
});
// 1,4,9,16
이제 받아온 todo 값에 따른 UI를 보여줄 수 있도록 코드를 수정한다.
이때, 조건부 스타일링을 위해서 classNames를 사용한다.
// TodoListItem.js
import React from ‘react‘;
import {
MdCheckBoxOutlineBlank,
MdCheckBox,
MdRemoveCircleOutline,
} from ‘react-icons/md‘;
import cn from ‘classnames‘;
import ‘./TodoListItem.scss‘;
const TodoListItem = ({ todo }) => {
const { text, checked } = todo;
return (
<div className=“TodoListItem“>
<div className={cn(‘checkbox‘, { checked })}>
{checked ? <MdCheckBox /> : <MdCheckBoxOutlineBlank />}
<div className=“text“>{text}</div>
</div>
<div className=“remove“>
<MdRemoveCircleOutline />
</div>
</div>
);
};
export default TodoListItem;
TodoList 컴포넌트는 App.js에서 전달해준 todos 값에 따라 다른 내용을 보여준다.
1. value 상태 관리하기
입력창에 입력하는 값을 관리하기 위해 useState를 사용하여 value 상태(state)를 정의한다.
onChange 함수를 만들어서 컴포넌트가 리렌더링될 때마다 함수를 재사용하도록 useCallback Hook을 사용한다.
// TodoInsert.js
import React, { useState, useCallback } from ‘react‘;
import { MdAdd } from ‘react-icons/md‘;
import ‘./TodoInsert.scss‘;
const TodoInsert = () => {
const [value, setValue] = useState(“);
const onChange = useCallback(e => {
setValue(e.target.value);
}, []);
return (
<form className=“TodoInsert“>
<input
placeholder=“할 일을 입력하세요“
value={value}
onChange={onChange}
/>
<button type=“submit“>
<MdAdd />
</button>
</form>
);
};
export default TodoInsert;
➨ 입력창은 value 값과 onChange 함수를 만들지 않아도 입력 가능!
value 값과 onChange 함수는 단지 입력창에 무엇이 입력되었는지 알기 위해 사용하는 것들이다.
입력창에 입력된 값을 통해 잘 업데이트 되는지 확인하려면 리액트 개발자 도구를 사용한다.
💡 리액트 개발자 도구
브라우저에 나타난 리액트 컴포넌트를 심층분석할 수 있도록 도와주는 도구이다.
▶ 리액트 개발자 도구 설치하기: https://chrome.google.com/webstore/category/extensions
설치 후 크롬 개발자 도구를 열면 <도구> 탭에 Components가 나타난다.
리액트 개발자 도구를 통해 TodoInsert(입력창 컴포넌트)를 선택하면 Hooks의 state에 값이 잘 들어가는 지 확인할 수 있다.
2. todos 배열에 새 객체 추가하기
App 컴포넌트에서 todos 배열에 새 객체를 추가하기 위해 onInsert 함수를 만들어본다.
💡 props로 전달하는 함수는 useCallback을 사용하여 함수를 감싸는 것을 습관화하자.
// App.js
import React, { useState, useRef, useCallback } from ‘react‘;
import TodoTemplate from ‘./components/TodoTemplate‘;
import TodoInsert from ‘./components/TodoInsert‘;
import TodoList from ‘./components/TodoList‘;
const App = () => {
const [todos, setTodos] = useState([
{
id: 1,
text: ‘리액트의 기초 알아보기‘,
checked: true,
},
{
id: 2,
text: ‘컴포넌트 스타일링해 보기‘,
checked: true,
},
{
id: 3,
text: ‘일정 관리 앱 만들어 보기‘,
checked: false,
},
]);
// 고윳값으로 사용될 id
// ref를 사용하여 변수 담기
const nextId = useRef(4);
const onInsert = useCallback(
text => {
const todo = {
id: nextId.current,
text,
checked: false,
};
setTodos(todos.concat(todo));
nextId.current += 1; // nextId 1씩 더하기
},
[todos],
);
return (
<TodoTemplate>
<TodoInsert onInsert={onInsert} />
<TodoList todos={todos} />
</TodoTemplate>
);
};
export default App;
3. TodoInsert에서 onSubmit 이벤트 설정하기
버튼을 클릭하면 일정이 추가되는 이벤트를 설정하도록 한다.
App.js에서 TodoInsert에 넣어준(=props로 전달한) onInsert 함수에서 파라미터로 value를 호출한다.
// TodoInsert.js
import React, { useState, useCallback } from ‘react‘;
import { MdAdd } from ‘react-icons/md‘;
import ‘./TodoInsert.scss‘;
const TodoInsert = ({ onInsert }) => {
const [value, setValue] = useState(“);
const onChange = useCallback(e => {
setValue(e.target.value);
}, []);
const onSubmit = useCallback(
e => {
onInsert(value);
setValue(“); // value 값 초기화
// submit 이벤트는 브라우저에서 새로고침을 발생시킵니다.
// 이를 방지하기 위해 이 함수를 호출합니다.
e.preventDefault();
},
[onInsert, value],
);
return (
<form className=“TodoInsert“ onSubmit={onSubmit}>
<input
placeholder=“할 일을 입력하세요“
value={value}
onChange={onChange}
/>
<button type=“submit“>
<MdAdd />
</button>
</form>
);
};
export default TodoInsert;
onSubmit 함수를 만들고 form의 onSubmit으로 설정한다.
onSubmit 함수를 호출하면 onInsert 함수를 value 값을 파라미터로 넣어서 호출하고
setValue를 통해 현재 value 값을 초기화한다.
➨ onSubmit 이벤트는 브라우저를 새로고침시키기 때문에 e.preventDefault() 함수를 호출하여 새로고침을 방지한다.
onClick 이벤트로 처리하기
const onClick = useCallback(
() => {
onInsert(value);
setValue(''); // value 값 초기화
},
[onInsert, value],
);
💡 form과 onSubmit을 사용하는 이유
입력창에서 <Enter>을 눌렀을 때도 이벤트를 발생시킨다.
➨ onClick으로 구현하기 위해서는 onKeyPress 이벤트를 통해 <Enter>를 감지하는 코드를 작성할 필요가 있다.
리액트 컴포넌트에서 배열의 불변성 + 배열 원소 제거 ➨ 배열 내장 함수 filter 사용
💡 배열 내장 함수: filter 함수
기존의 배열은 그대로 둔 상태에서 특정 조건을 만족하는 원소들만 추출하여 새로운 배열을 만든다.
const array = [1,2,3,4,5,6,7,8,9,10];
const biggerThanFive = array.filter(number => number >5);
조건을 확인해주는 함수를 파라미터로 넣어야 한다. 파라미터로 넣은 함수는 true 또는 false를 반환한다.
true를 반환한 경우의 값만 새로 만드는 배열에 포함한다.
1. todos 배열에서 id로 항목 지우기
onRemove 함수 전달: App.js ➨ TodoList.js ➨TodoListItem.js
filter 함수를 사용하여 App.js에서 onRemove 함수를 작성해본다.
// App.js
import React, { useState, useRef, useCallback } from ‘react‘;
import TodoTemplate from ‘./components/TodoTemplate‘;
import TodoInsert from ‘./components/TodoInsert‘;
import TodoList from ‘./components/TodoList‘;
const App = () => {
(…)
const onRemove = useCallback(
id => {
setTodos(todos.filter(todo => todo.id != = id));
},
[todos],
);
return (
<TodoTemplate>
<TodoInsert onInsert={onInsert} />
<TodoList todos={todos} onRemove={onRemove} />
</TodoTemplate>
);
};
export default App;
App.js에서 id를 파라미터 값으로 받아오고 같은 id 항목을 todos 배열에서 제거한다.
그리고 onRemove 함수는 todoList의 props로 설정한다.
2. TodoListItem에서 삭제 함수 호출하기
onRemove 함수를 사용하려면 TodoList 컴포넌트를 거쳐 TodoListItem에서 사용할 수 있도록 구현한다.
props로 받은 onRemove 함수를 TodoListItem에 props 형태로 그대로 전달한다.
// TodoList.js
import React from ‘react‘;
import TodoListItem from ‘./TodoListItem‘;
import ‘./TodoList.scss‘;
const TodoList = ({ todos, onRemove }) => {
return (
<div className=“TodoList“>
{todos.map(todo => (
<TodoListItem todo={todo} key={todo.id} onRemove={onRemove} />
))}
</div>
);
};
export default TodoList;
3. TodoListItem에서 삭제 함수 호출하기
TodoListItem에서 onRemove 함수에 현재 객체 자신이 가진 id 값을 넣어서 삭제 함수를 호출하도록 구현한다.
// TodoListItem.js
import React from 'react';
import {
MdCheckBoxOutlineBlank,
MdCheckBox,
MdRemoveCircleOutline,
} from 'react-icons/md';
import cn from 'classnames';
import './TodoListItem.scss';
const TodoListItem = ({ todo, onRemove }) => {
const { id, text, checked } = todo;
return (
<div className="TodoListItem">
<div className={cn('checkbox', { checked })}>
{checked ? <MdCheckBox /> : <MdCheckBoxOutlineBlank />}
<div className="text">{text}</div>
</div>
<div className="remove" onClick={() => onRemove(id)}>
<MdRemoveCircleOutline />
</div>
</div>
);
};
export default TodoListItem;
onToggle 함수를 App에 만들고 해당 함수를 TodoList 컴포넌트에게 props로 넣어준다.
TodoList를 통해 TodoListItem 컴포넌트에 전달한다.
onToggle 함수 전달: App.js ➨ TodoList.js ➨TodoListItem.js
1. onToggle 구현하기
App.js에서 일정 목록을 수정하는 기능을 가진 onToggle 함수를 작성한다.
그리고 TodoList 컴포넌트에 onToggle 함수를 props로 넘긴다.
// App.js
import React, { useState, useRef, useCallback } from 'react';
import TodoTemplate from './components/TodoTemplate';
import TodoInsert from './components/TodoInsert';
import TodoList from './components/TodoList';
const App = () => {
(...)
const onToggle = useCallback(
id => {
setTodos(
todos.map(todo =>
todo.id === id ? { ...todo, checked: !todo.checked } : todo,
),
);
},
[todos],
);
return (
<TodoTemplate>
<TodoInsert onInsert={onInsert} />
<TodoList todos={todos} onRemove={onRemove} onToggle={onToggle} />
</TodoTemplate>
);
};
export default App;
2. TodoListItem에서 onToggle 함수 호출하기
// TodoList.js
import React from ‘react‘;
import {
MdCheckBoxOutlineBlank,
MdCheckBox,
MdRemoveCircleOutline,
} from ‘react-icons/md‘;
import cn from ‘classnames‘;
import ‘./TodoListItem.scss‘;
const TodoListItem = ({ todo, onRemove, onToggle }) => {
const { id, text, checked } = todo;
return (
<div className=“TodoListItem“>
<div className={cn(‘checkbox‘, { checked })} onClick={() => onToggle(id)}>
{checked ? <MdCheckBox /> : <MdCheckBoxOutlineBlank />}
<div className=“text“>{text}</div>
</div>
<div className=“remove“ onClick={() => onRemove(id)}>
<MdRemoveCircleOutline />
</div>
</div>
);
};
export default TodoListItem;
TodoListItem은 props로 onToggle 함수를 받았다.
이제 onToggle 함수를 TodoList에서 호출할 수 있도록 코드를 수정한다.
➨ TodoListItem에서 onClick 이벤트가 발생했을 때 함수를 호출한다.
// TodoListItem.js
import React from 'react';
import {
MdCheckBoxOutlineBlank,
MdCheckBox,
MdRemoveCircleOutline,
} from 'react-icons/md';
import cn from 'classnames';
import './TodoListItem.scss';
const TodoListItem = ({ todo, onRemove, onToggle }) => {
const { id, text, checked } = todo;
return (
<div className="TodoListItem">
<div className={cn('checkbox', { checked })} onClick={() => onToggle(id)}>
{checked ? <MdCheckBox /> : <MdCheckBoxOutlineBlank />}
<div className="text">{text}</div>
</div>
<div className="remove" onClick={() => onRemove(id)}>
<MdRemoveCircleOutline />
</div>
</div>
);
};
export default TodoListItem;
1. 일정 관리 프로젝트에서, 입력창에 value와 onChange를 설정하지 않더라도 ( 리액트 개발자 도구 )을/를 통해 어떤 값이 입력되었는지 추적할 수 있다.
2. props로 전달해야 할 함수를 만들 때는 (useCallBack)을 사용하여 함수를 감싸는 것을 습관화하는 것이 좋다.
3. onSubmit 이벤트는 브라우저를 새로고침 시키는데, 프로젝트에서는 onSubmit 이벤트가 발생할 때 새로고침을 방지하기 위해 (e.preventDefault()) 함수를 호출하면 새로고침을 방지할 수 있다.
4. (filter) 함수는 기존의 배열을 그대로 둔 상태에서 특정 조건을 만족하는 원소들만 따로 추출하여 새로운 배열을 만들어 줍니다.
5. 배열 내장 함수 map을 통해 컴포넌트로 변환하여 렌더링이 가능하다. 이때 map을 사용하여 컴포넌트 형태로 변환할 때는 (key) props를 전달해주어야 한다.
6. 입력창을 구현하는 TodoInsert(입력창)에서 onsubmit 이벤트 말고도 (onclick) 이벤트로도 구현이 가능하다. 하지만 onsubmit과 form 함수로 구현하는 것이 효율적인 이유는 입력창에서 (enter)을 눌렀을 때 이벤트가 발생하기 때문이다.
7. TodoInsert(입력창)에서 값의 변화가 발생했을 때, onChange 함수를 만들어서 컴포넌트가 리렌더링될 때마다 함수를 재사용하도록 (useCallback) Hook을 사용
1. 버튼을 클릭하면 발생할 이벤트에 대한 코드를 작성하자.
//TodoInsert.js
const TodoInsert = ({ onInsert }) => {
const [value, setValue] = useState('');
const onChange = useCallback(e => {
// 이 부분을 작성하기
}, []);
const onSubmit = useCallback(
e => {
// 이 부분을 작성하기
},
[onInsert, value],
);
2. App.js에서 onToggle(일정 목록 수정)과 onRemove(일정 목록 삭제) 함수를 구현해보자
const onRemove = useCallback(
id => {
// 이 부분을 구현하기
},
[todos],
);
const onToggle = useCallback(
id => {
setTodos(
//이 부분을 구현하기
),
);
},
[todos],
);
Corner React Starter #2
Editor 유숨숨
<리액트를 다루는 기술> 12장: immer를 사용하여 더 쉽게 불변성 유지하기 (0) | 2022.01.17 |
---|---|
<리액트를 다루는 기술> 11장: 컴포넌트 성능 최적화 (0) | 2022.01.17 |
<리액트를 다루는 기술> 9장: 컴포넌트 스타일링 (0) | 2022.01.03 |
<리액트를 다루는 기술> 8장: Hooks (0) | 2021.12.27 |
<리액트를 다루는 기술> 7장: 컴포넌트의 라이프사이클 메서드 (0) | 2021.12.27 |