Notice
Recent Posts
Recent Comments
Link
JiSoo's Devlog
[Udemy React 완벽 가이드] Section 15 본문
양식
- 개발자 시각에서 폼은 폼과 그 입력 때문에 넓고 다양한 상태를 나타낼 수 있어 굉장히 복잡할 수 있다
- 하나 이상의 입력 값이 모두 유효하지 않을 수도 있으며 모두 유효할 수도 있고 심지어는 서버로 리퀘스트를 보낸 뒤에 특정 값이 사용 가능한지 확인해야 하는 비동기 유효성 검사를 이용해야 해서 상태를 알 수 없을 수도 있다
- input 요소에서 포커스를 잃었을 때 입력값의 유효성을 검증하는 경우에 좋은 점은 전체 폼이 제출되고 경고 메시지를 보내기 전에 사용자가 유효한 값을 입력할 수 있다는 것이다
양식 제출 처리 및 사용자 입력 값 가져오기
- 사용자 입력을 가져오는 방법에는 크게 두 가지가 있는데 모든 키 입력마다 확인하며 이 값들을 어떤 상태 변수에 저장할 수 있고 ref를 이용해 사용자가 값을 모두 입력했을 때 입력 값을 가져올 수도 있다
- 폼 안에 있는 버튼을 통해 폼이 제출되면 웹사이트를 제공하는 서버로 HTTP 요청을 보내게 되는데 이 과정은 자동적으로 일어나며 브라우저가 자동적으로 웹사이트를 제공하는 서버로 HTTP 요청을 보낸다
- ref는 항상 current 프로퍼티를 갖는 객체이므로 리액트에서 ref는 항상 current 프로퍼티를 갖게 된다
- 즉각적인 유효성 검증을 위해 키 입력마다 입력 값이 필요하다면 ref로는 이 작업이 불가하므로 상태를 사용하는 것이 좋다
기본 검증 추가하기
if(enteredName.trim() == ''){
return;
}
"was touched" State 처리하기
const SimpleInput = (props) => {
const nameInputRef = useRef();
const [enteredName, setEnteredName] = useState("");
const [enteredNameIsValid, setEnteredNameIsValid] = useState(false);
const [enteredNameTouched, setEnteredNameTouched] = useState(false);
useEffect(()=>{
if(enteredNameIsValid){
console.log('Name Input is valid!');
}
},[enteredNameIsValid])
const nameInputChangeHandler = (event) => {
setEnteredName(event.target.value);
};
const formSubmissinHandler = (event) => {
event.preventDefault();
setEnteredNameTouched(true);
if (enteredName.trim() == "") {
setEnteredNameIsValid(false);
return;
}
setEnteredNameIsValid(true);
console.log(enteredName);
const enteredValue = nameInputRef.current.value;
console.log(enteredValue);
//nameInputRef.current.value = ""; =>NOT IDEAL, DON'T MANIPULATE THE DOM
setEnteredName("");
};
const nameInputIsInValid = !enteredNameIsValid && enteredNameTouched;
const nameInputClasses = enteredNameIsValid
? "form-control invalid"
: "form-control";
return (
<form onSubmit={formSubmissinHandler}>
<div className={nameInputClasses}>
<label htmlFor="name">Your Name</label>
<input
ref={nameInputRef}
type="text"
id="name"
onChange={nameInputChangeHandler}
value={enteredName}
/>
{nameInputIsInValid && (
<p className="error-text">Name must not be empty.</p>
)}
</div>
<div className="form-actions">
<button>Submit</button>
</div>
</form>
);
};
초점을 잃은 리액트
- onBlur핸들러는 자바스크립트 이벤트로 input 요소가 포커스를 따라서 여기에 새로운 함수를 추가하고 event를 써서 바인딩한다
const nameInputBlurHandler = event=>{
setEnteredNameTouched(true);
if (enteredName.trim() == "") {
setEnteredNameIsValid(false);
return;
}
}
<input
ref={nameInputRef}
type="text"
id="name"
onChange={nameInputChangeHandler}
onBlur={nameInputBlurHandler}
value={enteredName}
/>
리팩토링 및 State 파생
import {useState } from "react";
const SimpleInput = (props) => {
const [enteredName, setEnteredName] = useState("");
const [enteredNameTouched, setEnteredNameTouched] = useState(false);
const enteredNameIsValid = enteredName.trim() !=='';
const nameInputIsInValid = !enteredNameIsValid && enteredNameTouched;
const nameInputChangeHandler = (event) => {
setEnteredName(event.target.value);
};
const nameInputBlurHandler = event=>{
setEnteredNameTouched(true);
}
const formSubmissinHandler = (event) => {
event.preventDefault();
setEnteredNameTouched(true);
if (!enteredNameIsValid) {
return;
}
setEnteredNameIsValid(true);
console.log(enteredName);
//nameInputRef.current.value = ""; =>NOT IDEAL, DON'T MANIPULATE THE DOM
setEnteredName("");
setEnteredNameTouched(false);
};
const nameInputClasses = enteredNameIsValid
? "form-control invalid"
: "form-control";
return (
<form onSubmit={formSubmissinHandler}>
<div className={nameInputClasses}>
<label htmlFor="name">Your Name</label>
<input
type="text"
id="name"
onChange={nameInputChangeHandler}
onBlur={nameInputBlurHandler}
value={enteredName}
/>
{nameInputIsInValid && (
<p className="error-text">Name must not be empty.</p>
)}
</div>
<div className="form-actions">
<button>Submit</button>
</div>
</form>
);
};
export default SimpleInput;
전체 양식 유효성 관리하기
- 전체 양식이 유효하기 위해서는 모든 입력이 유효해야 한다
let formIsValid =false;
if(enteredNameIsValid){
formIsValid=true;
}
~~~~
<button disabled={!formIsValid}>Submit</button>
사용자 지정 입력 훅 추가하기
- 커스텀 훅을 이용해 상태에 관련된 모든 로직을 다룰 수 있다
SimpleInput.js
import { useState } from "react";
import useInput from "../hooks/use-input";
const SimpleInput = (props) => {
const {
value: enteredName,
isValid: enteredNameIsValid,
hasError: nameInputHasError,
valueChangeHandler: nameChangedHandler,
inputBlurHandler: nameBlurHandler,
reset: resetNameInput,
} = useInput((value) => value.trim() !== "");
const [enteredEmail, setEnteredEmail] = useState("");
const [enteredEmailTouched, setEnteredEmailTouched] = useState(false);
const enteredEmailIsValid = enteredEmail.includes("@");
const enteredEmailIsInvalid = !enteredEmailIsValid && enteredEmailTouched;
let formIsValid = false;
if (enteredNameIsValid && enteredEmailIsValid) {
formIsValid = true;
}
const emailInputChangeHandler = (event) => {
setEnteredEmail(event.target.value);
};
const emailInputBlurHandler = (event) => {
setEnteredEmailTouched(true);
};
const formSubmissionHandler = (event) => {
event.preventDefault();
if (!enteredNameIsValid) {
return;
}
console.log(enteredName);
// nameInputRef.current.value = ''; => NOT IDEAL, DON'T MANIPULATE THE DOM
resetNameInput();
setEnteredEmail("");
setEnteredEmailTouched(false);
};
const nameInputClasses = nameInputHasError
? "form-control invalid"
: "form-control";
const emailInputClasses = enteredEmailIsInvalid
? "form-control invalid"
: "form-control";
return (
<form onSubmit={formSubmissionHandler}>
<div className={nameInputClasses}>
<label htmlFor="name">Your Name</label>
<input
type="text"
id="name"
onChange={nameChangedHandler}
onBlur={nameBlurHandler}
value={enteredName}
/>
{nameInputHasError && (
<p className="error-text">Name must not be empty.</p>
)}
</div>
<div className={emailInputClasses}>
<label htmlFor="email">Your E-Mail</label>
<input
type="email"
id="email"
onChange={emailInputChangeHandler}
onBlur={emailInputBlurHandler}
value={enteredEmail}
/>
{enteredEmailIsInvalid && (
<p className="error-text">Please enter a valid email.</p>
)}
</div>
<div className="form-actions">
<button disabled={!formIsValid}>Submit</button>
</div>
</form>
);
};
export default SimpleInput;
use-input.js
import { useState } from "react";
const useInput = (validateValue) => {
const [enteredValue, setEnteredValue] = useState("");
const [isTouched, setIsTouched] = useState(false);
const valueIsValid = validateValue(enteredValue);
const hasError = !valueValid && isTouched;
const valueChangeHandler = (event) => {
setEnteredValue(event.target.value);
};
const inputBlurHandler = (event) => {
setIsTouched(true);
};
const reset = () => {
setEnteredValue("");
setIsTouched(false);
};
return {
value: enteredValue,
isValid: valueIsValid,
hasError,
valueChangeHandler,
inputBlurHandler,
reset
};
};
export default useInput;
useReducer() 사용하기
import { useReducer } from "react";
const initialInputState = {
value: "",
isTouched: false,
};
const inputStateReducer = (state, action) => {
if (action.type === "INPUT") {
return { value: action.value, isTouched: state.isTouched };
}
if (action.type === "BLUR") {
return { isTouched: true, value: state.value };
}
if (action.type === "RESET") {
return { isTouched: false, value: "" };
}
return inputStateReducer;
};
const useInput = (validateValue) => {
const [inputState, dispatch] = useReducer(
inputStateReducer,
initialInputState
);
const valueIsValid = validateValue(inputState.value);
const hasError = !valueIsValid && inputState.isTouched;
const valueChangeHandler = (event) => {
dispatch({ type: "INPUT", value: event.target.value });
};
const inputBlurHandler = (event) => {
dispatch({ type: "BLUR" });
};
const reset = () => {
dispatch({ type: "RESET" });
};
return {
value: inputState.value,
isValid: valueIsValid,
hasError,
valueChangeHandler,
inputBlurHandler,
reset,
};
};
export default useInput;
728x90
'Frontend > React' 카테고리의 다른 글
[ReactJS로 영화 웹 서비스 만들기] Section 2 (1) | 2024.01.08 |
---|---|
[ReactJS로 영화 웹 서비스 만들기] Section 1 (0) | 2024.01.05 |
[Udemy React 완벽 가이드] Section 14 (1) | 2024.01.04 |
[Udemy React 완벽 가이드] Section 13 (2) | 2024.01.04 |
[Udemy React 완벽 가이드] Section 12 (1) | 2024.01.04 |