위와 같은 화면이 있다. 성을 입력하는 필드에 무언가는 입력하면 Hi! 옆에 입력된 글자가 나오고
이름 필드에 입력 한 글자는 Hi! 와 성 옆에 나오게 만들어보자.
즉, 아래와 같은 결과물이 나와야 한다.
우선 처음으로 만든 소스 코드를 보자.
import React, { useState } from "react";
function App() {
const [fName, setFName] = useState("");
const [lName, setLName] = useState("");
function updateFName(event) {
const firstName = event.target.value;
setFName(firstName);
}
function updateLName(event) {
const lastName = event.target.value;
setLName(lastName);
}
return (
<div className="container">
<h1>
Hi! {fName} {lName}
</h1>
<form>
<input
name="fName"
onChange={updateFName}
placeholder="성을 입력하세요."
value={fName}
autoComplete="off"
/>
<input
name="lName"
onChange={updateLName}
placeholder="이름을 입력하세요."
value={lName}
autoComplete="off"
/>
<button>입력</button>
</form>
</div>
);
}
export default App;
성과 이름 input에 onChange 이벤트를 걸고 updateFName, updateLName 메서드로 성과 이름을 실시간으로 세팅하는 방식으로 문제를 해결했다.
하지만 조금 수정할 부분이 보인다.
구조 분해도 성과 이름은 나누어주고, 성과 이름을 바꿔주는 메서드도 중복된다.
성과 이름은 하나로 묶어서 처리하는 방식으로 코드를 수정했다.
import React, { useState } from "react";
function App() {
const [fullName, setFullName] = useState({
fName: "",
lName: ""
});
function handleChange(event) {
const newValue = event.target.value;
const inputName = event.target.name;
console.log(newValue);
console.log(inputName);
if (inputName === "fName") {
setFullName({ fName: newValue });
} else if (inputName === "lName") {
setFullName({ lName: newValue });
}
}
return (
<div className="container">
<h1>
Hi! {fullName.fName} {fullName.lName}
</h1>
<form>
<input
name="fName"
onChange={handleChange}
placeholder="성을 입력하세요."
value={fullName.fName}
autoComplete="off"
/>
<input
name="lName"
onChange={handleChange}
placeholder="이름을 입력하세요."
value={fullName.lName}
autoComplete="off"
/>
<button>입력</button>
</form>
</div>
);
}
export default App;
App 컴포넌트의 상부를 보면 성과 이름으로 나누는 대신 fullName으로 구조 분해를 해주고 useState()에는 fName과 lName이 들어가 있는 객체로 초기화를 해줬다.
렌더링 부분에는 기존에 {fName} 대신 객체에 접근해야 하기 때문에 fullName.fName으로 변경했다. input의 value에도 수정을 해준다.
그리고 중복되던 메서드를 지워주고 handleChange라는 하나의 메서드를 만들어 주었다.
이벤트가 발생할 때 어떤 Input에서 이벤트가 들어오는지 확인하기 위해서 inputName이라는 변수를 만들어 구분할 때 사용해 주었다.
그리고 조건문을 통해서 fullName 객체 값을 수정하게 했다.
이제 이벤트 처리가 잘 되는지 보자!
뭔가 이상하다!!! 이름을 작성하면 성이 없어진다....
왜 그럴까???
조건문에서 setFullName 메서드를 사용할 때 문제가 발생하는 것이다.
if (inputName === "fName") {
setFullName({ fName: newValue });
} else if (inputName === "lName") {
setFullName({ lName: newValue });
}
가장 왼쪽 사진은 fullName의 초기값이다. fName, lName 모두 빈 스트링으로 잘 되어있다.
가운데 사진은 성 input에 "홍"이라는 값을 입력했을 때이다.
lName이 없어졌다!!! 왜냐하면 조건문에서 처리되는 setFullName 속 객체에는 fName값만 있기 때문에 이렇게 다시 초기화되는 것이다.
그리고 가장 오른쪽 사진은 이름에 "길동"을 입력했을 때고 성과 마찬가지로 조건문에서 초기화될 때 fName 요소 없이 세팅되면서 발생하는 문제점이다.
그럼 이걸 어떻게 해결해야 할까?
const [fullName, setFullName] = useState({
fName: "",
lName: ""
});
조건문에서도 fName과 lName 중 하나만이 아닌 둘 다 수정해주면 문제는 간단히 해결된다.
그렇지만, 성 필드에 값이 입력될 때는 이름의 값이 무엇인지 알아야 하고, 이름 필드에 입력 시에도 반대로 성의 값을 알아야 한다.
useState()를 통해서 나온 메서드인 setFullname()에는 이전 값을 파라미터로 받을 수 있는 기능이 있다.
파라미터로 prevValue를 넣고 새로 입력된 값이 아닌 기존의 값을 사용해야 하는 부분에 넣어주면 문제를 해결할 수 있다.
import React, { useState } from "react";
function App() {
fullName 초기화 부분
function handleChange(event) {
const newValue = event.target.value;
const inputName = event.target.name;
// ---------------------------------------------변경 부분
setFullName((prevValue) => {
if (inputName === "fName") {
return {
fName: newValue,
lName: prevValue.lName
};
} else if (inputName === "lName") {
return {
fName: prevValue.fName,
lName: newValue
};
}
});
}
// ---------------------------------------------변경 부분
return (
렌더링 부분
);
}
export default App;
원하는 대로 잘 동작한다!!!!
'TIL' 카테고리의 다른 글
OSI 모델이란!? (0) | 2022.04.05 |
---|---|
프로토콜이란!? (0) | 2022.04.05 |
useState()로 간단한 이벤트를 처리해보자! (0) | 2022.03.31 |
배열과 객체의 구조 분해 할당을 알아보자! (0) | 2022.03.31 |
리액트의 Hook을 알아보자! (0) | 2022.03.31 |