Notice
Recent Posts
Recent Comments
Link
«   2026/02   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
Archives
Today
Total
관리 메뉴

사고쳤어요

[React / ts] useState 사용법과 간단한 To-Do List 만들기 본문

웹 풀스택

[React / ts] useState 사용법과 간단한 To-Do List 만들기

kevinmj12 2025. 4. 8. 23:28

useState()

useState()는 리액트에서 컴포넌트의 상태를 관리하기 위해 사용되는 Hook(훅)이다.

기본적인 사용법은 다음과 같다.

const [state, setState] = useState(initialValue);

 

  • state: 현재 상태 값
  • setState: 상태를 변경할 수 있는 함수
  • initialValue: 상태의 초기값

 

 

타입스크립트에서는 타입을 명시하여 사용할 수 있다.

const [state, setState] = useState<type>(initialValue);
  • type: initialValue, state의 타입

 

useState에서는 일반적인 String, Number 등의 타입뿐만 아니라 객체, 배열 등 또한 사용할 수 있다.

interface User {
  name: string;
  age: number;
}

const [user, setUser] = useState<User>({ name: 'Minje', age: 30 });
const [hobbies, setHobbies] = useState<string[]>(["listening music", "watching movie"]);

 

setState를 사용하여 상태 변경이 가능한데, 아래 예제와 같이 사용할 수 있다.

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <p>현재 카운트: {count}</p>
      <button onClick={handleClick}>증가</button>
    </div>
  );
}

handleClcik()이라는 함수에서 setCount를 호출하여 그 값을 count + 1로 바꿔주었다.

그리고 button에서 onClick={handleClick}을 통해 버튼을 클릭하면 handleClick이 이루어지고,

setCout(count+1)이 실행되어 count의 값이 1 증가하게 된다.

 

간단한 To-Do List 만들기

import { useState } from "react";

type Todo = {
  id: number;
  text: string;
  isChecked: boolean;
};

const Todolist: React.FC = () => {
  const title: string = "오늘 할 일";

  const [todos, setTodos] = useState<Todo[]>([
    {
      id: 1,
      text: "공부하기",
      isChecked: false,
    },
    {
      id: 2,
      text: "잠자기",
      isChecked: false,
    },
    {
      id: 3,
      text: "미팅하기",
      isChecked: false,
    },
  ]);
  return (
    <div className="container">
      <h1>{title}</h1>

      <div className="board">
        {todos.map((todo) => (
          <div key={todo.id}>
            <input type="checkbox"></input>
            <span>{todo.text}</span>
          </div>
        ))}
      </div>
    </div>
  );
};

export default Todolist;

기본적인 스켈레톤 코드이다.

위에서 인터페이스로 타입을 만들어 useState()를 사용했던 것처럼, Todo라는 타입을 만들어 useState()를 사용하였다.

체크박스를 눌러 완료 여부를 체크할 수는 있지만, 이는 껍데기만 존재하고 실제로는 아무 일도 수행하지 않는다.

 

체크박스 선택 시 취소선 긋기

import { useState } from "react";

type Todo = {
  id: number;
  text: string;
  isChecked: boolean;
};

const Todolist: React.FC = () => {
  const title: string = "오늘 할 일";

  const [todos, setTodos] = useState<Todo[]>([
    {
      id: 1,
      text: "공부하기",
      isChecked: false,
    },
    {
      id: 2,
      text: "잠자기",
      isChecked: false,
    },
    {
      id: 3,
      text: "미팅하기",
      isChecked: false,
    },
  ]);

  const handleCheckedChange = (itemId: number) => {
    setTodos((prevItems) =>
      prevItems.map((item) =>
        item.id === itemId ? { ...item, isChecked: !item.isChecked } : item
      )
    );
  };

  return (
    <div className="container">
      <h1>{title}</h1>

      <div className="board">
        {todos.map((todo) => (
          <div key={todo.id}>
            <input
              type="checkbox"
              onClick={() => handleCheckedChange(todo.id)}
            ></input>
            <span>{todo.isChecked ? <del>{todo.text}</del> : todo.text}</span>
          </div>
        ))}
      </div>
    </div>
  );
};

export default Todolist;

새로운 handleCheckedChange()라는 함수를 만들고 그 안에 로직을 처리해주었다.

삼항 연산자와 스프레드 연산자가 섞여있어 헷갈릴 수 있지만 itemId에 해당되는 todo의 isChecked 값을 변경해주는 함수이다.

그리고 return 문에도 삼항연산자를 통하여 isChecked인 경우 취소선을 긋도록 설정해주었다.

 

새로운 To-Do 추가하기

import { useState } from "react";

type Todo = {
  id: number;
  text: string;
  isChecked: boolean;
};

const Todolist: React.FC = () => {
  const title: string = "오늘 할 일";

  const [todos, setTodos] = useState<Todo[]>([
    {
      id: 1,
      text: "공부하기",
      isChecked: false,
    },
    {
      id: 2,
      text: "잠자기",
      isChecked: false,
    },
    {
      id: 3,
      text: "미팅하기",
      isChecked: false,
    },
  ]);
  const [newTodo, setNewTodo] = useState<string>("");

  const handleCheckedChange = (itemId: number) => {
    setTodos((prevItems) =>
      prevItems.map((item) =>
        item.id === itemId ? { ...item, isChecked: !item.isChecked } : item
      )
    );
  };

  const addTodo = () => {
    if (newTodo.trim() !== "") {
      setTodos([
        ...todos,
        {
          id: Date.now(),
          text: newTodo.trim(),
          isChecked: false,
        },
      ]);
      setNewTodo("");
    }
  };

  return (
    <div className="container">
      <h1>{title}</h1>
      <div>
        <input
          type="text"
          placeholder="To-Do 추가"
          onChange={(e) => setNewTodo(e.target.value)}
          style={{
            marginRight: "10px",
            marginBottom: "20px",
          }}
        />
        <button
          onClick={() => {
            addTodo();
          }}
        >
          추가
        </button>
      </div>

      <div className="board">
        {todos.map((todo) => (
          <div key={todo.id}>
            <input
              type="checkbox"
              onClick={() => handleCheckedChange(todo.id)}
            ></input>
            <span>{todo.isChecked ? <del>{todo.text}</del> : todo.text}</span>
          </div>
        ))}
      </div>
    </div>
  );
};

export default Todolist;

newTodo라는 새로운 useState()를 만들어 input의 값을 저장하도록 하였다.

input의 onChange에 setNewTodo()를 설정하여 input값이 변할 때마다 newTodo는 그 값으로 업데이트된다.

마지막으로 "추가" 버튼을 누르면 작성한 To-Do가 추가된다.

 

 

기존 To-Do 삭제하기

import { useState } from "react";

type Todo = {
  id: number;
  text: string;
  isChecked: boolean;
};

const Todolist: React.FC = () => {
  const title: string = "오늘 할 일";

  const [todos, setTodos] = useState<Todo[]>([
    {
      id: 1,
      text: "공부하기",
      isChecked: false,
    },
    {
      id: 2,
      text: "잠자기",
      isChecked: false,
    },
    {
      id: 3,
      text: "미팅하기",
      isChecked: false,
    },
  ]);
  const [newTodo, setNewTodo] = useState<string>("");

  const handleCheckedChange = (itemId: number) => {
    setTodos((prevItems) =>
      prevItems.map((item) =>
        item.id === itemId ? { ...item, isChecked: !item.isChecked } : item
      )
    );
  };

  const addTodo = () => {
    if (newTodo.trim() !== "") {
      setTodos([
        ...todos,
        {
          id: Date.now(),
          text: newTodo.trim(),
          isChecked: false,
        },
      ]);
      setNewTodo("");
    }
  };

  const removeTodo = (itemId: number) => {
    setTodos(todos.filter((todo) => todo.id !== itemId));
  };

  return (
    <div className="container">
      <h1>{title}</h1>
      <div>
        <input
          type="text"
          placeholder="To-Do 추가"
          onChange={(e) => setNewTodo(e.target.value)}
          style={{
            marginRight: "10px",
            marginBottom: "20px",
          }}
        />
        <button
          onClick={() => {
            addTodo();
          }}
        >
          추가
        </button>
      </div>

      <div className="board">
        {todos.map((todo) => (
          <div key={todo.id}>
            <input
              type="checkbox"
              onClick={() => handleCheckedChange(todo.id)}
            ></input>
            <span>{todo.isChecked ? <del>{todo.text}</del> : todo.text}</span>
            <button
              className="delete-button"
              onClick={() => removeTodo(todo.id)}
            >
              삭제
            </button>
          </div>
        ))}
      </div>
    </div>
  );
};

export default Todolist;

removeTodo라는 함수를 만들어 todo를 제거하는 로직을 작성해주었고,

삭제 버튼을 새로 만들어 onClick에 removeTodo()를 등록하여 구현할 수 있다.