9-6. 항목 추가 기능 구현하기

송한솔·2023년 5월 20일
0

ReactStudy

목록 보기
52/54
post-thumbnail

이번에는 TodoInsert 컴포넌트를 통해 일정 항목을 추가하는 기능을 구현해보겠습니다.

먼저 기존에 만들었던 TodoInsert 컴포넌트를 수정해봅시다.

TodoInsert.js 수정

// TodoInsert.js
import { useCallback, useState } from 'react';
import { MdAdd } from 'react-icons/md';
import './TodoInsert.css';

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;

useCallback을 통해 전에 사용했던 함수를 재사용하여 리소스의 낭비를 줄여줍시다.


이제 확인해보면 이렇게 값을 추가하여도 아직 일정이 추가되지 않습니다.

onChange는 setValue()를 통해 일정에 들어갈 value값만 추적하고있고

아직 할일을 추가하지 않았기 때문입니다.


이제 App.js의 todos에 새로운 항목을 추가하는 onInsert함수를 만들어주겠습니다.

먼저 useCallback, 과 useRef를 import합시다

import { useState, useCallback, useRef } from 'react';

그리고 id로 활용할 useRef와 useCallback으로 onInsert함수를 넣어줍니다.

그리고 onInsert함수를 TodoInsert의 props로 전달합니다.

App.js 수정

import './reset.css';
import { useState, useCallback, useRef } from 'react';
import TodoInsert from "./components/TodoInsert";
import TodoTemplate from "./components/TodoTemplate";
import TodoList from './components/TodoList';

function 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);
  
  // 항목을 추가할 onIsert 함수 생성
  const onInsert = useCallback(
    text => {
      const todo = {
        id: nextId.current,
        text,
        checked: false,
      };
      setTodos(todos.concat(todo));
      nextId.current += 1; // nextId 1씩 더하기
    },
    [todos]
 );// 의존성 배열 ▼
   // todos가 변경될 때마다 새로운 함수가 생성됩니다.
   // 따라서, onInsert 함수는 항상 최신의 todos 배열을 참조하게 됩니다.


  return (
    <div>
      <TodoTemplate>
        <TodoInsert onInsert={onInsert}/> {/* 생성한 onInsert를 TodoInsert의 props로 설정 */}
        <TodoList todos ={todos}/>
      </TodoTemplate>
      
    </div>
  );
}

export default App;

의존성 배열이란?

useCallback과 의존성 배열(Dependency Array)

useCallback은 React의 Hook 중 하나로, 주로 성능 최적화에 사용됩니다.
useCallback은 첫 번째 파라미터로 전달된 함수를 메모이즈하고, 이를 반환합니다.
즉, 함수를 한 번 생성하고 나면 재사용하는 것이죠.

이 때 useCallback의 두 번째 파라미터로 배열을 전달하게 되는데, 이를 의존성 배열이라 합니다.

의존성 배열에는 해당 함수에서 참조하는 외부 값들을 넣어주게 됩니다. 그래서 이 값들이 변경되었을 때만 새로운 함수를 생성하도록 하며, 값이 변경되지 않았다면 이전에 생성된 함수를 재사용합니다.

TodoInsert.js 수정

지금부터 버튼을 클릭하면 발생할 이벤트를 설정합니다.
먼저 props로 받아온 onInsert를 받아옵시니다.

const TodoInsert = ({ onInsert }) => {

이제 onSubmit 함수를 만듭니다

const onSubmit = useCallback(e =>{
  onInsert(value);
  setValue('');
  // onSubmit이벤트는 새로고침을 강제합니다.
  e.preventDefault();
},
[onInsert, value]
);

이 함수가 호출되면 props로 받아온 onInsert 함수에 현재 값 value를 파라미터로 넣어서 호출합니다.
=> onChange 함수에 의해 value는 input에 적는순간 항상 추적됩니다.


생성한 onSubmit 함수를 Form의 onSubmit이벤트에 대입시켜주세요.

<form className='TodoInsert' onSubmit={onSubmit}>

이제 submit이 실행되면 e.preventDefault()에 의해 새로고침이 실행되지않고.
직접 만든 함수 onSubmit이 실행됩니다.

onClick으로도 똑같은 기능을 구현할 수 있지만 굳이 form과 onSubmit이벤트를 사용한 이유는
onSubmit이벤트의 경우 input에서 Enter를 눌렀을때도 발생하기 때문입니다.
onClick을 사용했다면 input에서 onKeyPress이벤트를 통해 Enter를 감지하는 로직을 새로 만들어야합니다.

결과

// TodoInsert.js
import { useCallback, useState } from 'react';
import { MdAdd } from 'react-icons/md';
import './TodoInsert.css';

const TodoInsert = ({onInsert}) => {
    const [value, setValue] = useState('');

    const onChange = useCallback(e => {
        setValue(e.target.value);
        console.log(e.target.value);
    }, []);

    const onSubmit = useCallback(
        e =>{
            onInsert(value);
            setValue('');
            // onSubmit이벤트는 새로고침을 강제합니다.
            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;

이제 새로 항목들이 제대로 추가되고 있나 확인해보세요.

0개의 댓글