한입 크기로 잘라먹는 리액트 강의를 수강하는 중에 새로운 방식을 알게 됐다.
이런 일기장을 만들 때 첫 번째 input이 작성자, 두 번째 input이 본문이라고 할 때
const [author, setAuthor] = useState("");
const [content, setContent] = useState("");
로 useState를 작성한다.
둘 다 input 안에 무언가를 작성할 때, 즉 change할 때 값을 상태 변화 함수에 넣어줘야 한다.
<input name="author" value={author} onChange={(e) => {setAuthor(e.target.value);}} />
<textarea name="content" value={content} onChange={(e) => {setContent(e.target.value);}} />
모두 미세한 차이가 있긴 하지만 구조 자체는 동일하다.
이럴 때 하나의 객체로 통째로 묶고 객체의 프로퍼티 개념으로 접근하면 코드의 중복이 없어진다.
const [state, setState] = useState({
author: "",
content: "",
});
위 코드처럼 state, setState로 묶고 초기값을 author, content 모두 빈 문자열로 넣어준다.
<input name="author" value={state.author} onChange={handleChangeState} />
<textarea name="content" value={state.content} onChange={handleChangeState} />
원래는 author, setAthor / content, setContet 였던 것들을 state 하나에 묶고 점 표기법으로 밸류값에 접근해 value를 가져왔다.
onChange 부분도 객체로 접근해준다.
<input
name="author"
value={state.author}
onChange={(e) => {
setState({
author: e.target.value,
content: state.content,
});
}}
/>
<textarea
name="content"
value={state.content}
onChange={(e) => {
setState({
content: e.target.value,
author: state.content,
});
}}
/>
입력하는 칸에 무언가를 입력, 즉 변화가 일어나면 value에 마지막 변화값이 나온다.
setState에 해당하는 칸 부분의 값을 변경시켜주되 각자 다른 객체는 그대로 유지하게 한다.
그런데 이게 지금 2개라서 content, author 모두 적을 수 있는 거지 이게 여러 개라면 쓰기가 힘들어진다.
이 때 스프레드 문법으로 기존의 것들은 모두 그대로 복사하고, 변경하는 것만 마지막 줄에 적어준다.
<input
name="author"
value={state.author}
onChange={(e) => {
setState({
...state,
author: e.target.value,
});
}}
/>
<textarea
name="content"
value={state.content}
onChange={(e) => {
setState({
...state,
content: e.target.value,
});
}}
/>
이랬더니 onChange 부분이 완전히 똑같은 것이 아닌가...
author면 author, content면 content가 나오게 해주면 되는 것만 다르다.
이 부분을 각 태그의 name으로 접근해본다.
const handleChangeState = (e) => {
setState({
...state,
[e.target.name]: e.target.value,
});
};
각자 onChange 부분에 직접 변화를 주기 보다 공통된 부분을 묶어 handleChangeState 함수를 만들었다.
이벤트 객체를 파라미터로, e.target.name과 해당되지 않는 것들은 스프레드 구문으로 그대로 복사해온다.
그리고 변경사항에 해당되는 부분은 name으로 접근하고 value를 가져오면 된다.
이모션 부분까지 추가한 전체 코드는 아래와 같다.
import React, { useState } from "react";
const DiaryEditor = () => {
const [state, setState] = useState({
author: "",
content: "",
emotion: 1,
});
const handleChangeState = (e) => {
setState({
...state,
[e.target.name]: e.target.value,
});
console.log(e.target.name);
console.log(e.target.value);
};
const handleSubmit = () => {
console.log(state);
alert("저장 성공");
};
return (
<div className="DiaryEditor">
<h2>오늘의 일기</h2>
<div>
<input
name="author"
value={state.author}
onChange={handleChangeState}
/>
</div>
<div>
<textarea
name="content"
value={state.content}
onChange={handleChangeState}
/>
</div>
<div>
<span>오늘의 감정 점수: </span>
<select
name="emotion"
value={state.emotion}
onChange={handleChangeState}
>
<option value={1}>1</option>
<option value={2}>2</option>
<option value={3}>3</option>
<option value={4}>4</option>
<option value={5}>5</option>
</select>
</div>
<div>
<button onClick={handleSubmit}>저장</button>
</div>
</div>
);
};
export default DiaryEditor;
그냥 습관적으로 쓰던 useState를 좀 더 이해하게 되었고 객체로 묶어 접근하는 관점을 접하게 돼 신기했다.
'⚛️ React > 💭 한 입 크기 React' 카테고리의 다른 글
[React] React.createContext로 Props Drilling 방지하기 (0) | 2023.07.26 |
---|---|
[React] useReducer로 상태 변화 로직을 분리하기 (0) | 2023.07.26 |
[React] React.memo로 컴포넌트 재사용하기 (0) | 2023.07.26 |
[React] useMemo로 연산한 값 재사용하기 (0) | 2023.07.26 |
[React] 리액트의 생애주기 (Mount, Update, Unmount) (0) | 2023.07.25 |