
지금까지는 어떠한 입력을 받아내는 행위를 하지 않았다.
아래 사진과 같은 사용자 인풋을 모으는 기능을 만들어보자.
App.js
return (
<NewPeople/>
);
NewPeople.js
const NewPeople = () => {
return (
<div className="new-people">
<NewPeopleForm/>
</div>
);
};
NewPeople.js
const NewPeopleForm = () => {
return (
<form>
<div className="new-people__controls" >
<div className="new-people__control">
<label> 나이 </label>
<input type="text"></input>
</div>
<div className="new-people__control">
<label> 몸무게 </label>
<input type="number" min="1" step="1" max="200"></input>
</div>
<div className="new-people__control" >
<label> 사는지역 </label>
<input type="text"></input>
</div>
</div>
<div className="new-people__actions">
<button type="submit"> 제출하기 </button>
</div>
</form>
);
};
사용자의 입력에 반응하고 반응값을 얻어오려면 어떻게 해야할까?
onChange, onInput같은 이벤트 리스너 사용시 자동으로 딸려오는 객체를 사용해준다. => event <=
NewPeople.js
const NewPeopleForm = () => {
const ageChangeHandler = (evenTT) => {
console.log(evenTT.target.value);
};
return (
<form>
...
<input type="text" onChange={ageChangeHandler}></input>
</form>
...
);
}
예를들어 위의 코드는 onChange 이벤트 리스너를 사용했는데,
이 Change 이벤트가 발생할때 바닐라 자바스크립트에서는 길고 복잡한 코드를 작성하여 객체를 얻어와야 했다.
하지만 리액트에서는 자동으로 Change 이벤트에 대한 event객체를 리턴해준다. 우리는 단지 인자 이름을 내마음대로 지어주고 사용하면된다.
(보통은 e 또는 event 임의로 지어도 된다는 의미로 evenTT로 지었다.)
그런다음 이벤트 객체(evenTT)에 대한 수많은 데이터중 target 필드를 참조한다.
target 필드는 이벤트가 발생한 DOM 요소를 자동 지목한다. Change의 경우 input이다.
input은 수많은 프로퍼티가 있지만 가장 중요한 값은 역시 value 프로퍼티.
value 프로퍼티는 이벤트가 발생한 시점에 입력되어 있는 값을 말한다.
즉 값을 얻어오려고 할때 evenTT.target.value 이 구문의 의미는
“ 이벤트가 발생한 객체에 대해 DOM 요소를 지목하고 (enenTT.target)
값을 보여줘 (.value) " 라고 해석 할 수 있다.
값을 수신만 하면 사용할 수 없을 것이다.
저장이 되어야 비로소 추후 사용이 가능하므로 값을 저장한뒤 컴포넌트가 재실행되어도 값이 남아있도록 해보자.컴포넌트가 재실행 되어도 값이 남아있다는 의미는 익숙한데, 여기서도 역시 useState를 사용하고 방법에는 두가지가 있다.
1. 여러 상태를 사용하는(개별상태 슬라이스) 방법
2. 한개의 상태로 묶는 형태의 방법
NewPeopleForm.js // 일부분만
const [enteredAge, setEnteredAge ]=useState('');
const ageChangeHandler = (event) => {
setEnteredAge(event.target.value);
};
event객체의 value값은 당연하지만 useState의 set 함수의 인자값으로 사용할 수 있다.
NewPeopleForm.js // 전체부분
동일한 방법으로 다른곳에서도 똑같이 써주면 된다.
const NewPeopleForm = () => {
const [enteredAge, setEnteredAge ]=useState('');
const [enteredWeight, setEnteredWeight ]=useState('');
const [enteredHome, setEnteredHome ]=useState('');
const ageChangeHandler = (event) => {
setEnteredAge(event.target.value);
};
const weightChangeHandler = (event) => {
setEnteredAge(event.target.value);
};
const homeChangeHandler = (event) => {
setEnteredAge(event.target.value);
};
return (
<form>
<div className="new-people__controls" >
<div className="new-people__control">
<label> 나이 </label>
<input type="text" onChange={ageChangeHandler}></input>
</div>
<div className="new-people__control">
<label> 몸무게 </label>
<input type="number" min="1" step="1" max="200" onChange={weightChangeHandler}></input>
</div>
<div className="new-people__control" >
<label> 사는지역 </label>
<input type="text" onChange={homeChangeHandler}></input>
</div>
</div>
<div className="new-people__actions">
<button type="submit"> 제출하기 </button>
</div>
</form>
);
};
NewPeopleForm.js // 일부분만
const NewPeopleForm = () => {
const [userInput, setUserinput] = useState({
enteredAge : '',
enteredWeight : '',
enteredHome : ''
});
const ageChangeHandler = (event) => {
setUserinput({
...userInput,
enteredAge : event.target.value
})
};
};
return (
<form>
<div className="new-people__controls" >
<div className="new-people__control">
<label> 나이 </label>
<input type="text" onChange={ageChangeHandler}></input>
</div>
</div>
</form>
);
};
상태 하나를 사용하는 방법은 useState사용시 초기값으로 객체를 받는것이다.
참고로 uesState의 set 함수를 각 핸들러에 대해 인자값으로 객체를 설정할때 스프레드 문법을 통해 모든 프로퍼티들을 설정해주지 않는다면 타겟의 프로퍼티를 제외한 나머지 프로퍼티들을 가져가지 않으므로 꼭 알아두자.
NewPeopleForm.js // 전체 부분
const NewPeopleForm = () => {
const [userInput, setUserinput] = useState({
enteredAge : '',
enteredWeight : '',
enteredHome : ''
});
const ageChangeHandler = (event) => {
setUserinput({
...userInput,
enteredAge : event.target.value
})
};
const weightChangeHandler = (event) => {
setUserinput({
...userInput,
enteredWeight : event.target.value
})
};
const homeChangeHandler = (event) => {
setUserinput({
...userInput,
enteredHome : event.target.value
})
};
return (
<form>
<div className="new-people__controls" >
<div className="new-people__control">
<label> 나이 </label>
<input type="text" onChange={ageChangeHandler}></input>
</div>
<div className="new-people__control">
<label> 몸무게 </label>
<input type="number" min="1" step="1" max="200" onChange={weightChangeHandler}></input>
</div>
<div className="new-people__control" >
<label> 사는지역 </label>
<input type="text" onChange={homeChangeHandler}></input>
</div>
</div>
<div className="new-people__actions">
<button type="submit"> 제출하기 </button>
</div>
</form>
);
};
newPeopleFrom.js
const ageChangeHandler = (event) => {
//setEnteredAge(event.target.value);
setUserInput( (prevState) => {
return { ...prevState, enteredAge : event.target.value };
});
};
const weightChangeHandler = (event) => {
//setEnteredAge(event.target.value);
setUserInput( (prevState) => {
return { ...prevState, enteredWeight : event.target.value };
});
};
const homeChangeHandler = (event) => {
//setEnteredAge(event.target.value);
setUserInput( (prevState) => {
return { ...prevState, enteredHome : event.target.value };
});
};
위 코드처럼 상태하나에 핸들러 하나로 1:1 대응방식으로 사용하는것은 당연하다. 틀린것이 아니라 자연스러운것이다.
하지만 이런 핸들러가 여러개로 흩어져 있는것을 하나로 묶는것도 역시 가능하다.
const inputChangeHandler = (identifier, value) => {
if (identifier === "age") {
setEnteredAge(value);
} else if (identifier === "weight") {
setEnteredWeight(value);
} else identifier === "home";
};
return (
...
<input
type="text"
onChange={(event) => {
inputChangeHandler("age", event.target.value);
}}
></input>
...
);
많은 대안을 살펴봤다. 이제는 양식을 제출하는것까지 해보자!
이때 주의할점이 Button 요소에 직접 이벤트 리스너(onsubmit)를 추가하는것보다
Form 요소에 이벤트 리스너(onSubmit)를 추가하는것이 좋다.
왜냐하면 브라우저에 내장된 기능으로써 Form 요소 안에 버튼이 있다 가정하고,
그 버튼의 이벤트 발생시 Form 요소 자체에서 이벤트를 발생시키기 때문이다.
따라서 처음부터 그냥 Form 요소 자체에 이벤트 리스너를 추가하자.
또 하나 알아야할점은 , 브라우저의 내장된 기능인 Form 요소의 Button 이벤트는 브라우저 자체의 페이지가 다시 로딩되버린다.
보통 우리가 원하는것은 이게 아닐것이다.
페이지 로딩을 막는 방법은 다행하게도 존재하는데 PreventDefalut 메소드를 사용하면 된다.
NewPeopleForm.js
const submitHandler = (event) => { // Submit 이벤트에대한 핸들러함수
event.preventDefault(); // 웹페이지의 로딩을 막기
const peopleData = {
age: enteredAge,
weight: enteredWeight,
home: enteredHome,
};
console.log(peopleData);
}
return (
<form onSubmit={submitHandler}> // 폼요소에 Submit 이벤트 리스너 작성
...
<div className="new-people__actions">
<button type="submit"> 제출하기 </button> // button 요소에 Submit 이벤트 리스너 작성하는것을 지양하자.
</div>
</form>
);
};