여러개의 input 관리 [React]
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
https://ko.legacy.reactjs.org/docs/faq-state.html
https://ko.legacy.reactjs.org/docs/state-and-lifecycle.html