[react] 상태 관리: 객체 업데이트, Immer 사용하기


객체로 작성된 state 업데이트


state는 객체를 포함하여 모든 종류의 JavaScript 값을 보유할 수 있다.
객체는 JavaScript에서 변경 가능하지만 state에 저장할 때는 변경 불가능한 것으로 취급해야 한다.
React에서는 state의 객체를 직접 변경하지 않고 교체한다.
state에 저장된 객체를 업데이트하려면 새 객체를 생성(또는 기존 객체의 복사본을 만든 다음) 해당 복사본을 사용하도록 state를 설정해야 한다.


const [position, setPosition] = useState({
  x: 0,
  y: 0,
});

// 이 코드는 상태에서 기존 객체를 수정하기 때문에 문제가 된다.
// React에서는 상태에 넣은 모든 JavaScript 객체를 읽기 전용으로 취급해야 한다.
// 변경하는 대신 항상 교체해야 한다.
position.x = e.clientX;
position.y = e.clientY;

// 새 객체 생성 후 set 함수에 전달
const nextPosition = {};
nextPosition.x = e.clientX;
nextPosition.y = e.clientY;
setPosition(nextPosition);

// set 함수로 객체 교체
setPosition({
  x: e.clientX,
  y: e.clientY,
});


중첩 객체를 변경하지 않고 업데이트하는 방법

스프레드 구문으로 객체 복사 후 업데이트하는 방법

import {useState} from 'react'

export default function Form() {
  const [person, setPerson] = useState({
    name: '홍길동',
    email: 'email@gmail.com',
    info: {
      age: "20"
      gender: "male",
      hobby: "coding",
    }
  })

  const handleNameChange = (e) => {
     setPerson({
      ...person,
      name: e.target.value
    });
  }

  const handleEmailChange = (e) => {
     setPerson({
      ...person,
      email: e.target.value
    });
  }

  const handleAgeChange = (e) => {
     setPerson({
      ...person,
      info: {
        ...person.info,
        age: e.target.value
      }
    });
  }

  const handleGenderChange = (e) => {
     setPerson({
      ...person,
      info: {
        ...person.info,
        gender: e.target.value
      }
    });
  }

  const handleHobbyChange = (e) => {
     setPerson({
      ...person,
      info: {
        ...person.info,
        hobby: e.target.value
      }
    });
  }

  return (
    <>
      <label>
        Name:
        <input value={person.name} onChange={handleNameChange} />
      </label>
      <label>
        Email:
        <input value={person.email} onChange={handleEmailChange} />
      </label>
       <label>
        Age:
        <input value={person.info.age} onChange={handleAgeChange} />
      </label>
      <label>
        Gender:
        <input value={person.info.gender} onChange={handleGenderChange} />
      </label>
      <label>
        Hobby:
        <input value={person.info.hobby} onChange={handleHobbyChange} />
      </label>
  )
}



Immer로 객체 복사를 덜 반복적으로 만드는 간결한 업데이트 방법

Immer 라이브러리 사용하기

npm install use-immer 설치 import { useImmer } from ‘use-immer’ 추가하기

import {useImmer} from 'use-immer'

export default function Form() {
  const [person, updatePerson] = useImmer({
    name: '홍길동',
    email: 'email@gmail.com',
    info: {
      age: "20"
      gender: "male",
      hobby: "coding",
    }
  })

  const handleNameChange = (e) => {
    updatePerson(draft => {
      draft.name = e.target.value;
    })
  }

  const handleEmailChange = (e) => {
     updatePerson(draft => {
      draft.email = e.target.value;
     });
  }

  const handleAgeChange = (e) => {
     updatePerson(draft => {
      draft.info.age => e.target.value;
     })
  }

  const handleGenderChange = (e) => {
     updatePerson(draft => {
      draft.info.gender => e.target.value;
     })
  }

  const handleHobbyChange = (e) => {
    updatePerson(draft => {
      draft.info.hobby =>  e.target.value;
    })
  }

  return (
    <>
      <label>
        Name:
        <input value={person.name} onChange={handleNameChange} />
      </label>
      <label>
        Email:
        <input value={person.email} onChange={handleEmailChange} />
      </label>
       <label>
        Age:
        <input value={person.info.age} onChange={handleAgeChange} />
      </label>
      <label>
        Gender:
        <input value={person.info.gender} onChange={handleGenderChange} />
      </label>
      <label>
        Hobby:
        <input value={person.info.hobby} onChange={handleHobbyChange} />
      </label>
  )
}





© 2023. by MyeongheeJung

Powered by MH.J