TIL - 20250826

juni·2025년 8월 26일

TIL

목록 보기
106/317

0826 React : 상태 관리, 데이터 흐름, 동적 렌더링


✅ 1. 객체로 상태값 관리하기

  • 관련 있는 여러 상태값들을 개별적인 useState로 선언하는 대신, 하나의 객체로 묶어 관리하면 코드를 더 간결하고 체계적으로 만들 수 있습니다. 특히 폼(Form)의 여러 입력 필드를 관리할 때 유용합니다.

➕ 상태 업데이트 시 주의사항

  • 객체 상태를 업데이트할 때는 반드시 이전 상태를 복사한 후, 변경하려는 값만 덮어써야 합니다. 그렇지 않으면 다른 속성값들이 사라지게 됩니다. 이때 스프레드 문법(...)을 사용하는 것이 일반적입니다.
import React, { useState } from 'react';

function ExpenseForm() {
  // 1. 여러 입력값을 하나의 객체 상태로 관리
  const [userInput, setUserInput] = useState({
    enteredTitle: '',
    enteredAmount: '',
    enteredDate: '',
  });

  const titleChangeHandler = (event) => {
    // 2. 이전 상태를 복사하고, 변경된 값만 덮어쓰기
    setUserInput((prevState) => {
      return { ...prevState, enteredTitle: event.target.value };
    });
  };

  // ... 다른 핸들러들도 유사하게 구현 ...

  return (
    <form>
      <input
        type="text"
        value={userInput.enteredTitle} // 상태와 UI를 연결
        onChange={titleChangeHandler}
      />
      {/* ... */}
    </form>
  );
}

✅ 2. 상향식 데이터 전달 (Lifting State Up)

  • React의 데이터 흐름은 기본적으로 하향식(Top-Down)입니다 (부모 → 자식, via Props). 자식 컴포넌트에서 발생한 데이터를 부모 컴포넌트로 전달해야 할 때는, 부모가 데이터를 처리할 함수를 자식에게 Props로 전달하고, 자식은 그 함수를 호출하는 방식을 사용합니다.

➕ 처리 흐름

  1. [부모] 데이터를 받아 처리할 함수를 정의합니다. (saveExpenseDataHandler)
  2. [부모] 해당 함수를 자식 컴포넌트에 Props로 전달합니다. (onSaveExpenseData={...})
  3. [자식] Props로 전달받은 함수를 특정 이벤트(e.g., 폼 제출)가 발생했을 때 호출합니다. 이때 전달할 데이터를 인자로 넘깁니다. (props.onSaveExpenseData(data))
  4. [부모] 함수가 호출되면서 자식의 데이터가 부모의 상태를 업데이트합니다.
// 부모 컴포넌트: NewExpense.js
function NewExpense(props) {
  // 1. 자식의 데이터를 받아 부모의 상태를 업데이트할 함수
  const saveExpenseDataHandler = (enteredExpenseData) => {
    const expenseData = {
      ...enteredExpenseData,
      id: Math.random().toString(),
    };
    props.onAddExpense(expenseData); // App.js로 다시 전달
  };

  return (
    <div>
      {/* 2. 자식에게 함수를 props로 전달 */}
      <ExpenseForm onSaveExpenseData={saveExpenseDataHandler} />
    </div>
  );
}

// 자식 컴포넌트: ExpenseForm.js
function ExpenseForm(props) {
  const submitHandler = (event) => {
    event.preventDefault();
    const expenseData = { /* ... 폼 데이터 ... */ };
    
    // 3. props로 받은 함수를 호출하여 데이터를 위로 전달
    props.onSaveExpenseData(expenseData);
  };

  return <form onSubmit={submitHandler}>{/* ... */}</form>;
}

✅ 3. 동적 리스트 렌더링

  • 배열에 담긴 데이터를 화면에 목록 형태로 렌더링할 때는 JavaScript의 map() 메서드를 사용합니다. map()은 배열의 각 요소를 순회하며, 각 요소를 JSX 엘리먼트로 변환한 새로운 배열을 반환합니다.

key Prop의 중요성

  • map()을 사용하여 리스트를 렌더링할 때는, 각 엘리먼트에 key라는 특별한 Prop을 반드시 포함해야 합니다.
  • key의 역할: React가 리스트의 항목이 변경, 추가, 또는 삭제되었을 때 어떤 항목을 변경해야 하는지 효율적으로 식별하기 위해 사용됩니다.
  • 좋은 key: 각 항목을 고유하게 식별할 수 있는 안정적인 값이어야 합니다. (e.g., 데이터의 id) 배열의 인덱스는 최후의 수단으로만 사용해야 합니다.
// Expenses.js
function Expenses(props) {
  return (
    <div>
      {/* 배열(props.items)을 map으로 순회하며 ExpenseItem 컴포넌트 렌더링 */}
      {props.items.map((expense) => (
        <ExpenseItem
          key={expense.id} // 각 항목을 식별할 고유한 key
          title={expense.title}
          amount={expense.amount}
          date={expense.date}
        />
      ))}
    </div>
  );
}

✅ 4. 조건부 렌더링

  • 특정 조건(State, Props 등)에 따라 다른 UI를 보여주는 것을 의미합니다. 이를 통해 동적이고 상황에 맞는 UI를 만들 수 있습니다.
방법사용 사례예시 코드
삼항 연산자if-else와 같이 두 가지 경우 중 하나를 렌더링할 때{isEditing ? <EditForm /> : <DisplayView />}
논리 && 연산자특정 조건이 참일 때만 엘리먼트를 렌더링할 때{isLoggedIn && <UserProfile />}
if문과 변수렌더링 로직이 복잡하여 JSX 밖에서 처리해야 할 때let content = <p>No items found.</p>;
if (items.length > 0) { ... }
return <div>{content}</div>;
// ExpensesList.js - 조건부 렌더링 예시
function ExpensesList(props) {
  // 1. if문과 변수를 사용한 복잡한 조건 처리
  if (props.items.length === 0) {
    return <h2 className="expenses-list__fallback">Found no expenses.</h2>;
  }

  return (
    <ul className="expenses-list">
      {props.items.map((expense) => (
        <ExpenseItem
          key={expense.id}
          title={expense.title}
          amount={expense.amount}
          date={expense.date}
        />
      ))}
    </ul>
  );
}```

---

### 📌 요약

*   관련 있는 상태는 **하나의 객체**로 묶어 관리하되, 업데이트 시에는 **스프레드 문법(`...`)**으로 이전 상태를 보존해야 합니다.
*   자식에서 부모로 데이터를 전달할 때는, 부모가 **함수를 Props로 내려주고** 자식이 그 함수를 **호출**하는 **상향식 데이터 전달** 패턴을 사용합니다.
*   배열 데이터를 UI 목록으로 변환할 때는 **`map()`** 메서드를 사용하며, 각 항목에는 반드시 고유한 **`key` Prop**을 지정해야 합니다.
*   상황에 따라 다른 UI를 보여주기 위해 **삼항 연산자, `&&` 연산자, `if`문** 등 다양한 **조건부 렌더링** 기법을 활용합니다.

0개의 댓글