[React] 상태(state) 관리 및 업데이트 방법

summereuna🐥·2023년 3월 10일
2

React JS

목록 보기
27/69

한 컴포넌트 내에서 여러개의 상태를 업데이트해야할 때 어떻게 해야할까?

1. 각각 따로 구분하여 다수의 state 생성하여 상태 관리 및 업데이트


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

const ExpenseForm = () => {
  //이벤트 타겟 값 항상 string으로 읽으니까 초기값 다 ""으로 하자구
  //🔥 상태를 각각 따로따로 만드는 방법
  const [enteredTitle, setEnteredTitle] = useState("");
  const [enteredAmount, setEnteredAmount] = useState("");
  const [enteredDate, setEnteredDate] = useState("");
  
  const titleChangeHandler = (e) => {
    setEnteredTitle(e.target.value);
    console.log("Title changed!");
  };

  const amountChangeHandler = (e) => {
    setEnteredAmount(e.target.value);
    console.log("Amount changed!");
  };

  const dateChangeHandler = (e) => {
    setEnteredDate(e.target.value);
    console.log("Date changed!");
  };

  const onSubmit = (e) => {
    e.preventDefault();
    console.log("뉴뉴뉴");
  };
  return (
    <form onSubmit={onSubmit}>
      <div className="new-expense__controls">
        <div className="new-expense__controls">
          <label htmlFor="new-expense-name">물품</label>
          <input
            type="text"
            id="new-expense-name"
            onChange={titleChangeHandler}
          />
        </div>
        <div className="new-expense__controls">
          <label htmlFor="new-expense-amount">금액</label>
          <input
            type="number"
            min="0.01"
            step="0.01"
            id="new-expense-amount"
            onChange={amountChangeHandler}
          />
        </div>
        <div className="new-expense__controls">
          <label htmlFor="new-expense-date">날짜</label>
          <input
            type="date"
            min="2019-01-01"
            max="2023-12-31"
            id="new-expense-date"
            onChange={dateChangeHandler}
          />
        </div>
      </div>
      <div className="new-expense__actions">
        <button type="submit">
          추가하기
        </button>
      </div>
    </form>
  );
};

export default ExpenseForm;

2. 객체로 묶어 하나의 state를 만들어 상태 관리 및 업데이트


기존 상태에 의존하여 상태를 업데이트해야 할 경우 상태를 업데이트하는 방법 3가지

1. ❗️BAD

setUserInput({ enteredTitle: e.target.value });

  • 문제점: 하나의 값만 바꿔주기 때문에 객체에 다른 값은 날아가 버린다.
  • 객체 안에 세개의 값이 있기 때문에 나머지 기존 값을 복사해서 잃어버리지 않도록 수정해야 한다.
import { useState } from "react";
import "./ExpenseForm.css";

const ExpenseForm = () => {
  //이벤트 타겟 값 항상 string으로 읽으니까 초기값 다 ""으로 하자구
  //🔥객체로 묶어 관리하는 방법
  const [userInput, setUserInput] = useState({
    enteredTitle: "",
    enteredAmount: "",
    enteredDate: "",
  });
  
  const titleChangeHandler = (e) => {
    // ❗️BAD
    setUserInput({ enteredTitle: e.target.value });
    console.log("Title changed!");
  };

  const amountChangeHandler = (e) => {
    // ❗️BAD
    setUserInput({ enteredAmount: e.target.value });
    console.log("Amount changed!");
  };

  const dateChangeHandler = (e) => {
    // ❗️BAD
    setUserInput({ enteredDate: e.target.value });
    console.log("Date changed!");
  };

//...

2. 🥺 Not Bad, But Not Best!

setUserInput({ ...userInput, enteredTitle: e.target.value });

기존 값을 복사하기 위해 이전 state의 스냅샷에 의존하여 이전 state 전체를 복사해온 후, 새로운 값을 오버라이드하는 방법이다.

  • 문제점: 이전 state에 의존하여 state를 업데이트하고 있다. 이 경우, 상태를 업데이트하는 함수를 위한 대체 폼을 사용해야 한다.
  • 많은 경우 2번째 방법을 사용해도 괜찮지만, 리액트가 상태 업데이트 스케줄(예약)을 가지고 있기 때문에 바로 실행하지는 않는다는 사실을 기억하자!
    동시에 수많은 상태 업데이트를 계획하면, 이 방법을 사용할 경우 오래되거나 잘못된 스냅샷에 의존할 수 있다.
import { useState } from "react";
import "./ExpenseForm.css";

const ExpenseForm = () => {
  //이벤트 타겟 값 항상 string으로 읽으니까 초기값 다 ""으로 하자구
  //🔥객체로 묶어 관리하는 방법
  const [userInput, setUserInput] = useState({
    enteredTitle: "",
    enteredAmount: "",
    enteredDate: "",
  });
  
  const titleChangeHandler = (e) => { 
    // 🥺 Not Bad, But Not Best!
    setUserInput({ ...userInput, enteredTitle: e.target.value });
    console.log("Title changed!");
  };

  const amountChangeHandler = (e) => {
    // 🥺 Not Bad, But Not Best!
    setUserInput({ ...userInput, enteredAmount: e.target.value });
    console.log("Amount changed!");
  };

  const dateChangeHandler = (e) => {
    // 🥺 Not Bad, But Not Best!
    setUserInput({ ...userInput, enteredDate: e.target.value });
    console.log("Date changed!");
  };

//...

3. 😇 Good!

setUserInput((prevState) => {
      return { ...prevState, enteredTitle: e.target.value };
    });

setState()함수를 호출하고 그 인자로 함수를 전달한다.
전달된 함수의 인자에는 이전 state값을 스냅샷을 받아 전달하고, 새로운 state의 스냅샷을 반환한다.

  • 이전 상태 값에 따라 상태를 업데이트할 경우 이 함수 구문이 베스트다.

  • 리액트가 상태 업데이트 스케줄(예약)을 가지고 있기 때문에 바로 실행하지는 않는다는 사실을 기억하자!
    3번으로 할 경우, 리액트는 이 안에 있는 함수에서 prevState 상태의 스냅샷이 가장 최신 상태의 스냅샷이라는 것과 항상 계획된 상태 업데이트를 염두에 두고 있다는 것을 보장한다.

  • 3번 방법은 항상 최신의 스냅샷으로 작업할 수 있도록 하는 안전한 방법이다. 따라서 이전 상태에 따라 상태를 업데이트를 해야 한다면 3번, 함수 구문을 사용하자!

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

const ExpenseForm = () => {
  //이벤트 타겟 값 항상 string으로 읽으니까 초기값 다 ""으로 하자구
  //🔥객체로 묶어 관리하는 방법
  const [userInput, setUserInput] = useState({
    enteredTitle: "",
    enteredAmount: "",
    enteredDate: "",
  });
  
  const titleChangeHandler = (e) => { 
    //😇 Good!
    setUserInput((prevState) => {
      return { ...prevState, enteredTitle: e.target.value };
    });
    console.log("Title changed!");
  };

  const amountChangeHandler = (e) => {
    // 😇 Good!
    setUserInput((prevState) => {
      return { ...prevState, enteredAmount: e.target.value };
    });
    console.log("Amount changed!");
  };

  const dateChangeHandler = (e) => {
    // 😇 Good!
    setUserInput((prevState) => {
      return { ...prevState, enteredDate: e.target.value };
    });
    console.log("Date changed!");
  };

//...
profile
Always have hope🍀 & constant passion🔥

0개의 댓글