[한 입 크기로 잘라 먹는 리액트] 리액트(React) 02

hidihyeonee·2025년 2월 3일
0

2025.02.03 작성

OS : Window
개발환경 : VScode
개발언어 : JavaScript
프레임워크 : React


[할 일 관리] 앱 만들기

중요한 개념 정리

1. useState - 상태 관리 (State Management)

const [content, setContent] = useState('');
  • useState를 사용해서 컴포넌트의 상태(state) 를 관리함.
  • 상태가 변경되면 자동으로 UI가 업데이트됨.
  • content 값이 변경될 때마다 setContent를 호출해서 값이 반영됨.

2. useRef - 변수 저장 & ID 관리

const idRef = useRef(3);
  • useRef는 렌더링이 일어나도 값이 유지됨.
  • useState를 사용하면 값이 변경될 때마다 재렌더링되지만, useRef는 재렌더링되지 않음.
  • 새로운 Todo 아이템을 추가할 때 고유한 ID 값을 생성하는 데 사용됨.
예제 - 새로운 Todo 추가 시 ID 증가
const onCreate = (content) => {
    const newItem = {
        id: idRef.current,  // 현재 ID 사용
        content,
        isDone: false,
        createDate: new Date().getTime(),
    };
    setTodo([newItem, ...todo]);
    idRef.current += 1; // 다음 ID 값 증가
};
  • idRef.current 값이 변경되어도 컴포넌트가 다시 렌더링되지 않음.
  • useState를 사용하면 불필요한 렌더링이 발생할 수 있음.

3. Props - 부모 → 자식 데이터 전달

const TodoEditor = ({onCreate}) => { ... }
  • 부모 컴포넌트에서 자식 컴포넌트로 데이터(또는 함수)를 전달하는 방법
  • App.js에서 TodoEditor에 onCreate 함수를 전달하여 새로운 Todo를 추가할 수 있게 함.
예제 - onCreate 함수를 TodoEditor에 전달
<TodoEditor onCreate={onCreate} />
  • TodoEditor에서 입력한 데이터를 부모(App.js)가 관리함.
  • 이렇게 하면 부모 컴포넌트에서 전체 상태를 관리할 수 있음.

주요 코드

App.js

import './App.css';
import Header from './component/Header';
import TodoEditor from './component/TodoEditor';
import TodoList from './component/TodoList';
import { useState, useRef } from 'react';

const mockTodo = [
  {
    id: 0,
    isDone: false,
    content: "React 공부하기",
    createDate: new Date().getTime,
  },
  {
    id: 1,
    isDone: false,
    content: "빨래 널기기",
    createDate: new Date().getTime,
  },
  {
    id: 2,
    isDone: false,
    content: "노래 연습하하기",
    createDate: new Date().getTime,
  },
];

function App() {
  const idRef = useRef(3);

  const [todo, setTodo] = useState(mockTodo);

  const onCreate = (content) => {
    const newItem = {
      id: idRef.current,
      content,
      isDone: false,
      createDate: new Date().getTime(),
    };
    setTodo([newItem, ...todo]);
    idRef.current += 1;
  };

  return (
    <div className="App">
      <Header />
      <TodoEditor onCreate={onCreate} />
      <TodoList />
    </div>
  );
}

export default App;

TodoEditor.js

import "./TodoEditor.css";
import { useState } from "react";

// props
// {} 쓰면 : 구조분해할당 --> 매개 변수명과 객체의 속성명이 일치하는 값 대입
// 안 쓰면 : 객체 --> onCreate = {onCreate:함수}

const TodoEditor = ({onCreate}) => {
    const [content, setContent] = useState('');
    const onChangeContent = (e) => {
        setContent(e.target.value);
    };

    return ( 
    <div className="TodoEditor">
        <h4>새로운 Todo 작성하기✏️</h4>
        <div className="editor_wrapper">
            <input placeholder="새로운 Todo..." value={content} onChange={onChangeContent}/>
            <button onClick={() => onCreate(content)}>추가</button>
        </div>
    </div>
    );
};

export default TodoEditor;

TodoEditor.css

.TodoEditor .editor_wrapper {
    width: 100%;
    display: flex;
    gap: 10px;
}

.TodoEditor input {
    flex: 1;
    box-sizing: border-box;
    border: 1px solid rgb(220, 220, 220);
    border-radius: 5px;
    padding: 15px;
}

.TodoEditor input:focus {
    outline: none;
    border: 1px solid #1f93ff;
}

.TodoEditor button {
    cursor: pointer;
    width: 80px;
    border: none;
    background-color: #1f93ff;
    color: white;
    border-radius: 5px;
}

TodoList.js

import TodoItem from "./TodoItem";
import "./TodoList.css"

const TodoList = () => {
    return <div className="TodoList">
        <h4>Todo List🌱</h4>
        <input className="searchbar" placeholder="검색어를 입력하세요" />
        <div className="list_wrapper">
            <TodoItem />
            <TodoItem />
            <TodoItem />
        </div>
    </div>;
};

export default TodoList;

TodoList.css

.TodoList .searchbar {
    margin-bottom: 20px;
    width: 100%;
    border: none;
    border-bottom: 1px solid rgb(220, 220, 220);
    box-sizing: border-box;
    padding-top: 15px;
    padding-bottom: 15px;
}

.TodoList .searchbar:focus {
    outline: none;
    border-bottom: 1px solid #1f93ff;
}

.TodoList .list_wrapper {
    display: flex;
    flex-direction: column;
    gap: 20px;
}

TodoItem.js

import "./TodoItem.css"

const TodoItem = () => {
    return (
        <div className="TodoItem">
            <div className="checkbox_col">
                <input type="checkbox" />
            </div>
            <div className="title_col">할 일</div>
            <div className="date_col">{new Date().toLocaleDateString()}</div>
            <div className="btn_col">
                <button>삭제</button>
            </div>
        </div>
    );
};

export default TodoItem;

TodoItem.css

.TodoItem {
    display: flex;
    align-items: center;
    gap: 20px;
    padding-bottom: 20px;
    border-bottom: 1px solid rgb(240, 240, 240);
}

.TodoItem .checkbox_col{
    width: 20px;
}

.TodoItem .title_col{
    flex: 1;
}

.TodoItem .date_col{
    font-size: 14px;
    color: gray;
}

.TodoItem .btn_col button {
    cursor: pointer;
    color: gray;
    font-size: 14px;
    border: none;
    border-radius: 5px;
    padding: 5px;
}

profile
벨로그 쫌 재밌네?

0개의 댓글