Javascript

여러개의 input 관리 [React]

muyeon 2024. 5. 17. 19:56
input 을 관리할때 onChange 와 value 를 통해 사용하고 useState 를 통해 관리한다.
더 관리하기 좋은 형태는 없을까?

무슨 고민이야?

 

아래 코드는 간단한 todo 리스트의 입력부분이다.

import React, { useState } from "react";
import "../../styles/index.css";
import TodoFormButton from "./buttons/TodoFormButton";

const TodoForm = ({ setTodos }) => {
  const [title, setTitle] = useState("");
  const [content, setContent] = useState("");

  const addTodoHandler = (e) => {
    e.preventDefault();
    if (!title || !content) {
      alert("빈칸은 허용되지 않습니다.");
      return;
    }

    const newTodo = {
      id: Date.now(),
      title,
      content,
      complete: false,
    };

    setTodos((prevTodos) => [...prevTodos, newTodo]);
    setTitle("");
    setContent("");
  };

  return (
    <div className="todo-form-wrapper">
      <form className="todo-form-container" onSubmit={addTodoHandler}>
        <div>
          <label htmlFor="title">제목</label>
          <input
            type="text"
            id="title"
            value={title}
            onChange={(e) => setTitle(e.target.value)}
          />
          <label htmlFor="content">내용</label>
          <input
            type="text"
            id="content"
            value={content}
            onChange={(e) => setContent(e.target.value)}
          />
        </div>
        <TodoFormButton />
      </form>
    </div>
  );
};

export default TodoForm;

 

고민점은 이렇다.

 

1. onChange 함수를 보면 set 하는 부분을 제외하면 동일하다.

2. 현재 코드는 input 이 늘어나면 useState 도 늘어나야 한다.

 

onChange 부분을 함수로 뺀다고 한들 set 부분이 다르기에 조건이 생겨 더욱 보기 안좋아 질 것이다.

 

이를 더 효율적으로 관리할 수 있는 방법은 뭐가있을까?


객체를 통한 관리

 

좋은 방법은 input 에 name 을 설정하고, 이벤트가 발생했을때 이를 참조한다.

 

객체 형태의 관리가 필요하다.

 

// ... 중략

const TodoForm = ({ setTodos }) => {
  const [inputs, setInputs] = useState({
    title: "",
    content: "",
  });

  const onChange = (e) => {
    
  };

  const addTodoHandler = (e) => {
    // ... 중략
  };

  return (
    <div className="todo-form-wrapper">
      <form className="todo-form-container" onSubmit={addTodoHandler}>
        <div>
          <label htmlFor="title">제목</label>
          <input
            type="text"
            id="title"
            name="title"
            value={title}
            onChange={onChange}
          />
          <label htmlFor="content">내용</label>
          <input
            type="text"
            id="content"
            name="content"
            value={content}
            onChange={onChange}
          />
        </div>
        <TodoFormButton />
      </form>
    </div>
  );
};

export default TodoForm;

 

이제 이 값을 참조해 객체를 업데이트 하면 된다.

 

이를 onChange 함수에서 구현한다.


어떻게 업데이트해?

 

구조분해 할당과 스프레드 연산자를 통해 업데이트 한다.

 

// ... 중략

const TodoForm = ({ setTodos }) => {
  const [inputs, setInputs] = useState({
    title: "",
    content: "",
  });

  const onChange = (e) => {
    const { name, value } = e.target;
    // name 은 input 의 name 이다.
    
    setInputs({
      ...inputs,
      [name]: value,
    })
    
  };

  // ... 중략

export default TodoForm;

 

  •  e.target.name 과 e.target.value 를 추출한다.
  •  ...inputs 를 사용해 기존 state 를 유지한다.
  •  [name]: value 를 사용해 변경된 필드를 업데이트한다.
  •  setInputs 를 사용해 업데이트된 state 를 설정한다.

주의점은 [name]: value 부분에 [] 를 넣어주지 않는다면 문자열 name 자체가 들어가져 name 값에 따라 다른 key 값이 변경된다.

 


변경된 코드

 

import React, { useState } from "react";
import "../../styles/index.css";
import TodoFormButton from "./buttons/TodoFormButton";

const TodoForm = ({ setTodos }) => {
  const [inputs, setInputs] = useState({
    title: "",
    content: "",
  });

  const { title, content } = inputs;

  const onChange = (e) => {
    const { name, value } = e.target;

    setInputs({
      ...inputs,
      [name]: value,
    });
  };

  const addTodoHandler = (e) => {
    e.preventDefault();
    if (!title || !content) {
      alert("빈칸은 허용되지 않습니다.");
      return;
    }

    const newTodo = {
      id: Date.now(),
      title,
      content,
      complete: false,
    };

    setTodos((prevTodos) => [...prevTodos, newTodo]);
    setInputs({
      title: "",
      content: "",
    });
  };

  return (
    <div className="todo-form-wrapper">
      <form className="todo-form-container" onSubmit={addTodoHandler}>
        <div>
          <label htmlFor="title">제목</label>
          <input
            type="text"
            id="title"
            name="title"
            value={title}
            onChange={onChange}
          />
          <label htmlFor="content">내용</label>
          <input
            type="text"
            id="content"
            name="content"
            value={content}
            onChange={onChange}
          />
        </div>
        <TodoFormButton />
      </form>
    </div>
  );
};

export default TodoForm;

 


마무리

 

이로서 여러개의 input이 있는 요구사항도 효율적으로 상태관리를 하는 방법에 대해 알게되었다.

중요한 점은 객체 상태를 업데이트 할 때는 꼭 기존의 상태를 한번 복사하고 특정값을 덮어씌워 새로운 값을 설정해야한다. -> 불변성

 

https://hsp0418.tistory.com/171

 

리액트 불변성이란 무엇이고, 왜 지켜야 할까?

들어가면서 리액트와 불변성의 연관 관계는 리액트가 지향하는 함수형 프로그래밍의 특징에서 발견할 수 있습니다. 함수형 프로그램밍의 특징 중 하나가 순수함수를 사용하는 것인데, 여기서

hsp0418.tistory.com

https://ko.legacy.reactjs.org/docs/faq-state.html

 

컴포넌트 State – React

A JavaScript library for building user interfaces

ko.legacy.reactjs.org

 

https://velog.io/@sunkim/React%EC%97%90%EC%84%9C-%EC%97%AC%EB%9F%AC%EA%B0%9C%EC%9D%98-input-%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC%ED%95%98%EA%B8%B0

 

[React]여러개의 input 상태 관리하기

input 여러 개 일때 useState를 여러개 사용하는건 좋은 방법이 아님. 좋은 방법은, input에 name이라는 값을 설정하고, 이벤트가 발생했을 때 이값을 참조하는거다. 여러개의 문자열 형태를 가지고 있

velog.io

https://ko.legacy.reactjs.org/docs/state-and-lifecycle.html

 

State and Lifecycle – React

A JavaScript library for building user interfaces

ko.legacy.reactjs.org