일정 항목을 추가하는 기능을 구현해 보자!
해당 기능을 구현하려면 TodoInsert 컴포넌트에서 인풋 상태를 관리하고,
App 컴포넌트에는 todos 배열에 새로운 객체를 추가하는 함수를 만들어줘야 한다.
①-1. TodoInsert 컴포넌트에서 인풋에 입력하는 값을 관리할 수 있도록 useState로 value라는 상태를 정의.
①-2. 추가로 인풋에 넣어 줄 onChange 함수도 작성해야 하는데, 이 과정에서 컴포넌트가 리렌더링될 때마다 함수를 새로 만드는 게 아니라 재사용할 수 있도록 useCallback Hook을 사용해보자.
import React, { useState, useCallback } from 'react';
import { MdAdd } from 'react-icons/md'; // 아이콘 사용
import './TodoInsert.scss';
// [ 아이콘 사용 방법 ]
// 사이트에서 사용하고 싶은 아이콘을 고르고, import 구문을 사용하여 불러옴
// 예시 : import { 아이콘 이름 } from 'react-icons/md';
const TodoInsert = () => {
const [value, setValue] = useState('');
const onChange = useCallback((e) => {
setValue(e.target.value);
}, []);
return (
<form className="TodoInsert">
{/* placeholder => 입력 필드(input, textarea 등)의 힌트 텍스트 */}
<input
placeholder="할 일을 입력하세요"
value={value}
onChange={onChange}
/>
<button type="submit">
<MdAdd />
</button>
</form>
);
};
export default TodoInsert;

todos 배열에 새 객체를 추가하는 onInsert 함수를 만들어 보자!
✔ 새로운 객체를 만들 때마다 id 값에 1씩 더해 줘야하는데, id 값은 useRef를 사용하여 관리할 예정!
❓🤔 useState가 아닌 useRef를 사용하여 컴포넌트에서 사용할 변수를 만드는 이유는 뭘까?
👉 id 값은 렌더링되는 정보가 아니기 때문!
✔ 이 값은 화면에 보이지도 않고, 이 값이 바뀐다고 해서 컴포넌트가 리렌더링될 필요도 없음. 단순히 새로운 항목을 만들 때 참조되는 값일 뿐임!
✔ 그리고 onInsert 함수는 컴포넌트의 성능을 아낄 수 있도록 useCallback으로 감싸주자!
props로 전달해야 할 함수를 만들 때는 useCallback을 사용해 함수를 감싸는 것을 습관화는 게 좋다.
②-1. onInsert 함수를 만들고, 해당 함수를 TodoInsert 컴포넌트의 props로 설정
import React, { useState, useRef, useCallback } from 'react';
import TodoTemplate from './components/TodoTemplate';
import TodoInsert from './components/TodoInsert';
import TodoList from './components/TodoList';
const App = () => {
/* todos 배열 안에 들어 있는 객체
=> 각 항목의 고유 id, 내용, 완료 여부를 알려 주는 값이 있음.
*/
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 /> */}
<TodoInsert onInsert={onInsert} />
{/* <TodoList /> */}
{/* todos 배열을 TodoList로 전달 */}
<TodoList todos={todos} />
</TodoTemplate>
);
};
export default App;
버튼을 클릭하면 발생할 이벤트를 설정해보자!
방금 App에서 TodoInsert에 넣어 준 onInsert 함수에 현재 useState를 통해 관리하고 있는 value 값을 파라미터로 넣어서 호출함.
③-1. onInsert 함수를 만든 뒤에는 해당 함수를 TodoInsert 컴포넌트의 props로 설정
import React, { useState, useRef, useCallback } from 'react';
import TodoTemplate from './components/TodoTemplate';
import TodoInsert from './components/TodoInsert';
import TodoList from './components/TodoList';
const App = () => {
/* todos 배열 안에 들어 있는 객체
=> 각 항목의 고유 id, 내용, 완료 여부를 알려 주는 값이 있음.
*/
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 /> */}
<TodoInsert onInsert={onInsert} />
{/* <TodoList /> */}
{/* todos 배열을 TodoList로 전달 */}
<TodoList todos={todos} />
</TodoTemplate>
);
};
export default App;
import React, { useState, useCallback } from 'react';
import { MdAdd } from 'react-icons/md'; // 아이콘 사용
import './TodoInsert.scss';
// [ 아이콘 사용 방법 ]
// 사이트에서 사용하고 싶은 아이콘을 고르고, import 구문을 사용하여 불러옴
// 예시 : import { 아이콘 이름 } from 'react-icons/md';
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}>
{/* placeholder => 입력 필드(input, textarea 등)의 힌트 텍스트 */}
<input
placeholder="할 일을 입력하세요"
value={value}
onChange={onChange}
/>
<button type="submit">
<MdAdd />
</button>
</form>
);
};
export default TodoInsert;


