[React] 기능 구현_②항목 추가 기능 구현

겨레·2024년 11월 26일

[React] 리액트 스터디

목록 보기
64/95

일정 항목을 추가하는 기능을 구현해 보자!

해당 기능을 구현하려면 TodoInsert 컴포넌트에서 인풋 상태를 관리하고,
App 컴포넌트에는 todos 배열에 새로운 객체를 추가하는 함수를 만들어줘야 한다.


① TodoInsert value 상태 관리하기

①-1. TodoInsert 컴포넌트에서 인풋에 입력하는 값을 관리할 수 있도록 useState로 value라는 상태를 정의.

①-2. 추가로 인풋에 넣어 줄 onChange 함수도 작성해야 하는데, 이 과정에서 컴포넌트가 리렌더링될 때마다 함수를 새로 만드는 게 아니라 재사용할 수 있도록 useCallback Hook을 사용해보자.

  • TodoInsert.jsx
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 배열에 새 객체 추가하기

todos 배열에 새 객체를 추가하는 onInsert 함수를 만들어 보자!

✔ 새로운 객체를 만들 때마다 id 값에 1씩 더해 줘야하는데, id 값은 useRef를 사용하여 관리할 예정!

❓🤔 useState가 아닌 useRef를 사용하여 컴포넌트에서 사용할 변수를 만드는 이유는 뭘까?
👉 id 값은 렌더링되는 정보가 아니기 때문!

✔ 이 값은 화면에 보이지도 않고, 이 값이 바뀐다고 해서 컴포넌트가 리렌더링될 필요도 없음. 단순히 새로운 항목을 만들 때 참조되는 값일 뿐임!

✔ 그리고 onInsert 함수는 컴포넌트의 성능을 아낄 수 있도록 useCallback으로 감싸주자!
props로 전달해야 할 함수를 만들 때는 useCallback을 사용해 함수를 감싸는 것을 습관화는 게 좋다.


②-1. onInsert 함수를 만들고, 해당 함수를 TodoInsert 컴포넌트의 props로 설정

  • App.jsx
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;



③ TodoInsert에서 onSubmit 이벤트 설정하기

버튼을 클릭하면 발생할 이벤트를 설정해보자!

방금 App에서 TodoInsert에 넣어 준 onInsert 함수에 현재 useState를 통해 관리하고 있는 value 값을 파라미터로 넣어서 호출함.


③-1. onInsert 함수를 만든 뒤에는 해당 함수를 TodoInsert 컴포넌트의 props로 설정

  • App.jsx
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;
  • TodoInsert.jsx
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;

profile
호떡 신문지에서 개발자로 환생

0개의 댓글