본문 바로가기
웹/React

[React] State로 사용자 입력관리하기2

by 천무지 2024. 7. 18.
반응형

 

 

지난 시간에 완성했던 코드를 살펴보자.

import React, { useState } from "react";

//간단한 회원가입 폼
//1. 이름
//2. 생년월일
//3. 국적
//4. 자기소개

const Register = () => {
  const [name, setName] = useState("너의이름은");
  const [birth, setBirth] = useState("");
  const [country, setCountry] = useState("");
  const [bio, setBio] = useState("");

  const onChangeName = (e) => {
    setName(e.target.value);
  };

  const onChangeBirth = (e) => {
    setBirth(e.target.value);
  };

  const onChangeCountry = (e) => {
    setCountry(e.target.value);
  };

  const onChangeBio = (e) => {
    setBio(e.target.value);
  };

  return (
    <div>
      <div>
        <input value={name} onChange={onChangeName} placeholder={"이름"} />
      </div>

      <div>
        <input value={birth} type={"date"} onChange={onChangeBirth} />
      </div>

      <div>
        <select value={country} onChange={onChangeCountry}>
          <option></option>
          <option value={"kr"}>한국</option>
          <option value={"us"}>미국</option>
          <option value={"uk"}>영국</option>
          <option value={"ch"}>중국</option>
        </select>
      </div>

      <div>
        <textarea value={bio} onChange={onChangeBio} />
      </div>
    </div>
  );
};

export default Register;

 

코드를 살펴보면 state의 선언도 그렇고 이벤트 핸들링 함수도 그렇고 반복되는 것들이 많이 보인다. 따라서 비효율적으로 보이기도 한다.

 

이 모든 state들을 하나의 객체로 만들었다면? 그리고 이벤트 핸들러들을 하나로 합칠 수 있다면?

 

이번에는 비효율적으로 보이는 코드를 깔끔하고 간결하게 개선해볼 것이다.

 

먼저 state들을 객체에 보관해서 관리해보자

import React, { useState } from "react";

//간단한 회원가입 폼
//1. 이름
//2. 생년월일
//3. 국적
//4. 자기소개

const Register = () => {
  const [input, setInput] = useState({
    name: "",
    birth: "",
    country: "",
    bio: "",
  });

  console.log(input);

  const onChangeName = (e) => {
    setInput({
      ...input,
      name: e.target.value,
    });
  };

  const onChangeBirth = (e) => {
    setInput({
      ...input,
      birth: e.target.value,
    });
  };

  const onChangeCountry = (e) => {
    setInput({
      ...input,
      country: e.target.value,
    });
  };

  const onChangeBio = (e) => {
    setInput({
      ...input,
      bio: e.target.value,
    });
  };

  return (
    <div>
      <div>
        <input
          value={input.name}
          onChange={onChangeName}
          placeholder={"이름"}
        />
      </div>

      <div>
        <input value={input.birth} type={"date"} onChange={onChangeBirth} />
      </div>

      <div>
        <select value={input.country} onChange={onChangeCountry}>
          <option></option>
          <option value={"kr"}>한국</option>
          <option value={"us"}>미국</option>
          <option value={"uk"}>영국</option>
          <option value={"ch"}>중국</option>
        </select>
      </div>

      <div>
        <textarea value={input.bio} onChange={onChangeBio} />
      </div>
    </div>
  );
};

export default Register;

기존에 있던 4개의 state들을 모두 지우고 새로운 state를 만들고 초기값으로 객체를 넣어주었다.

 

그리고 이벤트 헨들러 함수들은 더 이상 기존에 있던 상태 변화 함수를 사용할 수 없기 때문에 새롭게 만든 상태 변화 함수를 통해서 작성해주었다.

 

또한 이벤트 헨들러 내부에서 호출되는 상태 변화 함수의 인수로는 객체를 넣어 주었는데, 수정하고자 하는 값만 달랑 적어 버리면 객체 내부의 나머지 값들을 모두 날라가 버리기 때문에 스프레드 연산자로 기존의 값들을 적어주고, 변경하고자 하는 값을 이벤트 객체의 타켓 점 벨류로 설정하였다.

 

결과를 확인해보면

스프레드 연산자 덕에 기존에 객체 내부의 멤버들이 날라가지않고 잘 보존된 것을 알 수 있다.

 

 

 

다음으로 이벤트 헨들러도 사이즈를 줄여보자.

 

import React, { useState } from "react";

//간단한 회원가입 폼
//1. 이름
//2. 생년월일
//3. 국적
//4. 자기소개

const Register = () => {
  const [input, setInput] = useState({
    name: "",
    birth: "",
    country: "",
    bio: "",
  });

  const onChange = (e) => {
    setInput({
      ...input,
      [e.target.name]: e.target.value,
    });
  };

  return (
    <div>
      <div>
        <input
          name="name"
          value={input.name}
          onChange={onChange}
          placeholder={"이름"}
        />
      </div>

      <div>
        <input
          name="birth"
          value={input.birth}
          type={"date"}
          onChange={onChange}
        />
      </div>

      <div>
        <select name="country" value={input.country} onChange={onChange}>
          <option></option>
          <option value={"kr"}>한국</option>
          <option value={"us"}>미국</option>
          <option value={"uk"}>영국</option>
          <option value={"ch"}>중국</option>
        </select>
      </div>

      <div>
        <textarea name="bio" value={input.bio} onChange={onChange} />
      </div>
    </div>
  );
};

export default Register;

여기서 기존의 이벤트 핸들러들은 모두 지우고 onChange라는 새로운 이벤트 핸들러 함수를 작성해주었다.

 

근데 함수를 보면 초장에 이해하기가 쉽지 않다.

 

일단 모든 인풋, 텍스트 에리어, 셀렉트에 onChage로 이벤트 헨들러를 설정해 주었기 때문에 어디에서 어떤 것을 변경해도 onChange가 호출될 것이다.

 

함수가 실행이 되면 setInput이라는 상태변화 함수를 먼저 호출한다. 그리고 인수로는 객체를 만들어서 전달한다.

 

먼저 스프레드 연산자로 input의 값을 다 나열해 주었다. 

 

마지막에는 property의 key를 의미하는 자리에 대괄호를 열고 e.target.name을 작성하였다.

 

이 문법은 자바스크립트 객체 챕터에서 다루었었다.

 

새로운 객체를 만들면서 property의 key 자리에 대괄호를 열고 어떠한 변수의 이름을 작성하면, 어떠한 변수가 property의 key로서 설정이 된다. 

 

다시 말해서 e.target.name에 저장되어있는 값으로 key가 설정된 것이다.

 

그렇다면 e.target.name에는 어떤 값이 있는가??

 

여기에는 이벤트가 발생한 태그의 name 속성에 설정된 값이 들어있다.

 

예를 들어서 유저가 생년월일을 설정하면 코드상에서 두번째 인풋태그에서 이벤트가 발생한 것이다.

 

이때 이벤트의 타겟(e.target)은 두번째 인풋 태그 일 것이다. 이 태그의 속성에 있는 name은 birth로 설정되어있다.

 

따라서 이벤트 핸들러 함수 내부의 [e.target.name]은 결국 birth라는 의미로 해석된다.

 

결과적으로 birth의 e.target.value를 설정하라는 것으로 해석할 수 있는 것이다.

 

마찬가지로 bio를 수정한다면 textarea가 e.target이 되고, 이때 name의 값은 bio이기 때문에 onChange에서 [e.target.name]은 biofh 해석되고 결국 bio의 e.target.value를 설정하라는 것으로 해석된다.

 

 

 

비슷한 여러개의 state가 있을 때는 하나의 객체 값으로 묶어서 하나의 state로 통합해서 관리하면 더 편하다.

 

여러개의 비슷하게 생긴 이벤트 핸들러는 통합 이벤트 핸들러로 묶어줄 수 있다.

 

 

반응형