-
양식form 제출 처리 및 사용자 입력값 가져오기
import { useRef, useState } from "react"; const SimpleInput = (props) => { //useRef로 사용하는법 const nameInputRef = useRef(); const [enteredName, setEnteredName] = useState(''); //사용자 입력 가져오기(useState나, useRef로 가져올 수 있다) const nameInputChangeHandler = event => { setEnteredName(event.target.value) } //폼이 제출될 때 작동하는 함수 const formSubmissionHandler = event => { event.preventDefault(); console.log(enteredName) //useRef사용 const enteredValue = nameInputRef.current.value; console.log(enteredValue); //압력값 초기화 input value에서 state setEnteredName('') } return ( <form onSubmit={formSubmissionHandler}> <div className='form-control'> <label htmlFor='name'>Your Name</label> <input ref={nameInputRef}type='text' id='name' onChange={nameInputChangeHandler} value={enteredName}/> </div> <div className="form-actions"> <button>Submit</button> </div> </form> ); }; export default SimpleInput;
유효성 검증 추가
빈칸을 제출할 때 error 피드백 띄우기
import { useRef, useState } from "react"; const SimpleInput = (props) => { const nameInputRef = useRef(); const [enteredName, setEnteredName] = useState(''); //error출력 위한 상태 false로 하면 처음부터 error메세지가 뜨게 되므로 true로 설정해준다 const [enteredNameIsValid, setEnteredNameIsValid] = useState(true); //사용자 입력 가져오기(useState나, useRef로 가져올 수 있다) //함수 만들고 input에서 onChange로 함수를 연결해준다 const nameInputChangeHandler = event => { setEnteredName(event.target.value) } const formSubmissionHandler = event => { event.preventDefault(); //유효성 검증 //trim 공백제거 여기서 값이 없을 경우에 return하면 다음 줄이 실행되지 않는다 if(enteredName.trim() == '') { //입력값이 유효하지 않다면 false로 설정 setEnteredNameIsValid(false) return; } //앞의 조건문 다음으로 실행되는 것이 값이 유효하다는 의미이므로 true로 설정 setEnteredNameIsValid(true); console.log(enteredName) //useRef사용 const enteredValue = nameInputRef.current.value; console.log(enteredValue); //압력값 초기화 input value에서 state연결 후 사용가능 setEnteredName('') } //class를 이용해 입력부분 보이는 방식 바꾸기(css) //form-control class를 입력값이 유효하지 않을 때 css에서 설정한 form-control invalid로 변경 //true일 경우 form-control이 되고 false일 경우 orm-control invalid가 된다 //className에서 함수명nameInputClasses으로 지정해준다 const nameInputClasses = enteredNameIsValid ? 'form-control' : 'form-control invalid'; return ( <form onSubmit={formSubmissionHandler}> <div className={nameInputClasses}> <label htmlFor='name'>Your Name</label> <input ref={nameInputRef}type='text' id='name' onChange={nameInputChangeHandler} value={enteredName}/> {/**텍스트가 값이 유효하지 않을 때만 보이도록 설정 * enteredNameIsValid가 false일 때 p태그 표시 */} {!enteredNameIsValid && <p className="error-text">Name must not be empty.</p>} </div> <div className="form-actions"> <button>Submit</button> </div> </form> ); }; export default SimpleInput;
유효성 검증 코드 수정
import { useEffect, useRef, useState } from "react"; const SimpleInput = (props) => { const nameInputRef = useRef(); const [enteredName, setEnteredName] = useState(''); //error출력 위한 상태 생성 초기값 fasle 즉, 처음에는 입력된 값이 유효하지 않음을 의미 //false로 하면 처음부터 error메세지가 뜨게 되므로 true로 설정해준다-처음부터 true로 설정하는 것 맞지 않음 //false가 권장됨 그래서 true로 설정한 유효성 코드는 임시방편, 다른 방법으로 실행 const [enteredNameIsValid, setEnteredNameIsValid] = useState(false); //사용자가 입력을 건드렸을 경우,. const [enteredNameTouched, setEnteredNameTouched] = useState(false); //enteredNameIsValid가 변경될 때마다 실행,,, useEffect(()=> { if (enteredNameIsValid) { console.log('Name Input is valid'); } }, [enteredNameIsValid]) //사용자 입력 가져오기(useState나, useRef로 가져올 수 있다) //함수 만들고 input에서 onChange로 함수를 연결해준다 const nameInputChangeHandler = event => { setEnteredName(event.target.value) } //폼이 제출될 때 작동하는 함수 form onSubit으로 연결 const formSubmissionHandler = event => { //새로고침 막기 event.preventDefault(); //추가해준다 setEnteredNameTouched(true); //유효성 검증 //trim 공백제거 여기서 값이 없을 경우에 return하면 다음 줄이 실행되지 않는다 if(enteredName.trim() == '') { //입력값이 유효하지 않다면 false로 설정 setEnteredNameIsValid(false) return; } //앞의 조건문 뒤로 실행되는 것이 값 유효하다는 의미이므로 true로 설정 setEnteredNameIsValid(true); console.log(enteredName) //useRef사용 const enteredValue = nameInputRef.current.value; console.log(enteredValue); //useRef를 이용한 입력값 초기화->바람직하지 않음 useState사용 권장 // nameInputRef.current.value = ''; //압력값 초기화 input value에서 state연결 후 사용가능 setEnteredName('') } //앞의 값은 false이고 touched는 true일 때 true가 되도록 한다 //입력창이 건드려진 뒤면서 값이 유효하지 않을 때만 유효하지 않게 판단하기 위해서 const nameInputIsInvalid = !enteredNameIsValid && enteredNameTouched //class를 이용해 입력부분 보이는 방식 바꾸기 //form-control class를 입력값이 유효하지 않을 때 css에서 설정한 form-control invalid로 변경 //true일 경우 form-control이 되고,,false일 경우 orm-control invalid가 된다 //className에서 함수명nameInputClasses으로 지정해준다 //추가로 위에 함수를 지정했으므로 반대로 바꿈 const nameInputClasses = nameInputIsInvalid ? 'form-control invalid' : 'form-control' return ( <form onSubmit={formSubmissionHandler}> <div className={nameInputClasses}> <label htmlFor='name'>Your Name</label> <input ref={nameInputRef}type='text' id='name' onChange={nameInputChangeHandler} value={enteredName}/> {/**텍스트가 값이 유효하지 않을 때만 보이도록 설정 * enteredNameIsValid가 false일 때 p태그 표시 */} {nameInputIsInvalid && <p className="error-text">Name must not be empty.</p>} </div> <div className="form-actions"> <button>Submit</button> </div> </form> ); }; export default SimpleInput;
사용자가 입력할 때 errorr 표시
input요소가 포커스를 잃었을 때 유효성 검증
값이 유효하지 않은 상태에서 focus를 잃었을 때 사용자는 즉각적인 error메시지를 얻게 된다
//input요소가 focus를 잃었을 때 유효성 검증하기 위한 함수 input의 onBlur 연결 const nameInputBlurHandler =event => { //입력창에서 포커스를 잃었다는 것은 그 전에 사용자가 건드렸다는 것이고 입력할 기회가 있었다는 것 setEnteredNameTouched(true) //유효성 검증 enteredName확인 후 값이 유효하지 않으면 setEnteredNameIsValid false로 바꿔준다 if(enteredName.trim() == '') { setEnteredNameIsValid(false) return; } }
사용자가 키를 입력할 때마다 값이 유효한지 즉각적인 피드백을 받을 수 있도록 표시
키입력에 따라 고칠 수 있게 된다
const nameInputChangeHandler = event => { setEnteredName(event.target.value) //키 입력마다 유효성 검증하기 입력마다 검증해기 때문에 event.target.value if(event.target.value.trim() !== '') { //입력값이 유효하지 않다면 false로 설정 setEnteredNameIsValid(true) } }
리펙토링
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 formSubmissionHandler = event => { event.preventDefault(); setEnteredNameTouched(true); if(!enteredNameIsValid) { return; } console.log(enteredName) setEnteredName('') setEnteredNameTouched(false); } const nameInputClasses = nameInputIsInvalid ? 'form-control invalid' : 'form-control' return ( <form onSubmit={formSubmissionHandler}> <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;
여러 입력을 받을 경우 전체 form이 유효한지 확인 전체 양식이 유효하기 위해서는 모든 입력이 유효해야 한다
//deps에 폼의 입력의 모든 유효성 추가 enteredNameIsCalid 이 값이 바뀔 때마다 //useEffect가 다시 실행된다 컴포넌트가 처음 실행될 때도 실행된다 //useEffect에서는 모든 deps를 합친 뒤에 이 값이 모두 유효한지 확인하고 그렇다면 전체 폼이 유효하다고 설정한다 //useEffect를 사용하지 않아도 된다 이 대신 formIsValid와 useEffect를 없애고 //enteredNameIsValid와 다른 유효성의 값이 있다면 &&으로 확인 // useEffect(()=> { // if (enteredNameIsValid ) { // setFormIsValid(true); // } else { // setFormIsValid(false); // } // },[enteredNameIsValid]); //useEffect사용하지 않는 방법 let formIsValid = false; if (enteredNameIsValid ) { formIsValid = true; }
사용자 이메일 받아오고 올바른 이메일 주소인지 유효성 검증
import { useEffect, useState } from "react"; const SimpleInput = (props) => { const [enteredName, setEnteredName] = useState(''); const [enteredNameTouched, setEnteredNameTouched] = useState(false); //이메일 input관련 상태 const [enteredEmail, setEnteredEmail] =useState(''); const [enteredEmailTouched, setEnteredEmailTouched] = useState(false); const nameInputIsInvalid = !enteredNameIsValid && enteredNameTouched //이메일input enteredEmail이 @을 포함하는지 확인 이메일 관련 유효성 검사(간단한) const enteredEmailIsValid = enteredEmail.includes('@'); //위에서 만든 값이 false일 경우와 enteredEmailTouched가 true가 될 때 //이 상수를 이용해 classes로 유효하지 않을 경우의 style변화를 준다 //error메시지 출력활용에도 사용 const enteredEmailIsInValid = !enteredEmailIsValid && enteredEmailTouched //전체 폼 유효성 검증 let formIsValid = false; if (enteredNameIsValid && enteredEmailIsValid) { formIsValid = true; } const nameInputChangeHandler = event => { setEnteredName(event.target.value) } //email Input const emailInputChangeHandler = event => { setEnteredEmail(event.target.value) } const nameInputBlurHandler =event => { setEnteredNameTouched(true) } //email input요소가 focus를 잃었을 때 유효성 검증하기 위한 함수 input의 onBlur 연결 const emailInputBlurHandler = event => { setEnteredEmailTouched(true) } const formSubmissionHandler = event => { event.preventDefault(); setEnteredNameTouched(true); if(!enteredNameIsValid) { return; } console.log(enteredName) //폼 submit버튼 제출 후 초기화 setEnteredName('') setEnteredNameTouched(false); setEnteredEmail('') setEnteredEmailTouched(false); } const nameInputClasses = nameInputIsInvalid ? 'form-control invalid' : 'form-control'; //값이 유효하지 않을 경우의 email부분 style변경 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={nameInputChangeHandler} onBlur={nameInputBlurHandler}value={enteredName}/> {nameInputIsInvalid && <p className="error-text">Name must not be empty.</p>} </div> {/* 이메일input */} <div className={emailInputClasses}> <label htmlFor='name'>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;
사용자지정 custom hook 추가
hooks/use-input.js
//중복된 코드를 막기 위해 customhook사용 //입력값과 입력창이 건드려졌는지에 대한 상태를 다룬다(중복되는것들) import { useState } from "react"; //인자를 함수로 받는다 validateValue 이 매개변수가 함수를 값으로 받게 된다 const useInput = (validateValue) => { //제네릭한 이름으로 바꿔줌 enteredName,touched가져와서 valid부분도 이름 다 바꿔줌 const [enteredValue, setEnteredValue] = useState(""); //사용자가 입력을 건드렸을 경우 const [isTouched, setIsTouched] = useState(false); //인자로 매개변수 이름 설정 후valueIsValid를 validateValue에 enteredValue를 입력해 실행한 값으로 만든다 const valueIsValid = validateValue(enteredValue); //앞의 값은 false이고 touched는 true일 때 true가 되도록 한다 //입력창이 건드려진 뒤면서 값이 유효하지 않을 때만 유효하지 않게 판단하기 위해서 const hasError = !valueIsValid && isTouched; const valueChangeHandler = (event) => { setEnteredValue(event.target.value); }; //input요소가 focus를 잃었을 때 유효성 검증하기 위한 함수 input의 onBlur 연결 const inputBlurHandler = (event) => { //입력창에서 포커스를 잃었다는 것은 그 전에 사용자가 건드렸다는 것이고 //즉 입력할 기회가 있었다는 것 setIsTouched(true); }; //초기화(RESET) 함수 const reset = () => { setEnteredValue(""); setIsTouched(false); }; //값 반환 hasError의 결과도 반환 value반환 //모던 자바스크립트 문법으로 hasError 값 한번만 써준다 //이렇게 훅에서 정의된 함수들은 훅을 사용하는 컴포넌트에서 호출될 수 있다 return { value: enteredValue, isValid: valueIsValid, hasError, valueChangeHandler, inputBlurHandler, reset, }; }; export default useInput;
커스텀 훅 적용
import { useState } from "react"; //custom hook 불러오기 import useInput from "../hooks/use-input"; const SimpleInput = (props) => { //useInput호출하여 반환된 결과로부터 값을 추출(객체를 반환하므로 객체 디스트럭처링으로 키를 이용해 값을 가져온다) //value의 키값을 value:enteredName에 할당할 수 있다 이름 사용자설정 //customhook에서 값을 입력해줘야 한다 //함수를 다른 함수의 입력값으로 넣는 자바스크립트 문법 const { value: enteredName, isValid: enteredNameIsValid, hasError: nameInputHasError, valueChangeHandler: nameChangeHandler, 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); }; //폼이 제출될 때 작동하는 함수 form onSubit으로 연결 const formSubmissionHandler = (event) => { event.preventDefault(); if (!enteredNameIsValid) { return; } console.log(enteredName); //custom hook에서 가져온 reset 적용 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={nameChangeHandler} onBlur={nameBlurHandler} value={enteredName} /> {nameInputHasError && ( <p className="error-text">Name must not be empty.</p> )} </div> <div className={emailInputClasses}> <label htmlFor="name">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;
이메일에 대해 커스텀 훅 사용
//custom hook 불러오기 import useInput from "../hooks/use-input"; const SimpleInput = (props) => { //useInput호출하여 반환된 결과로부터 값을 추출(객체를 반환하므로 객체 디스트럭처링으로 키를 이용해 값을 가져온다) //value의 키값을 value:enteredName에 할당할 수 있다 이름은 짓기나름 //customhook에서 값을 입력해줘야 한다 //함수를 다른 함수의 입력값으로 넣는 자바스크립트 문법 const { value: enteredName, isValid: enteredNameIsValid, hasError: nameInputHasError, valueChangeHandler: nameChangeHandler, inputBlurHandler: nameBlurHandler, reset: resetNameInput, } = useInput((value) => value.trim() !== ""); const { value: enteredEmail, isValid: enteredEmailIsValid, hasError: emailInputHasError, valueChangeHandler: emailChangeHandler, inputBlurHandler: emailBlurHandler, reset: resetEmailInput, } = useInput((value) => value.includes("@")); let formIsValid = false; if (enteredNameIsValid && enteredEmailIsValid) { formIsValid = true; } const formSubmissionHandler = (event) => { event.preventDefault(); if (!enteredNameIsValid) { return; } console.log(enteredName); //custom hook에서 가져온 reset함수 적용 resetNameInput(); resetEmailInput(); }; const nameInputClasses = nameInputHasError ? "form-control invalid" : "form-control"; //값이 유효하지 않을 경우의 email부분 style변경 ? const emailInputClasses = emailInputHasError ? "form-control invalid" : "form-control"; return ( <form onSubmit={formSubmissionHandler}> <div className={nameInputClasses}> <label htmlFor="name">Your Name</label> <input type="text" id="name" onChange={nameChangeHandler} onBlur={nameBlurHandler} value={enteredName} /> {nameInputHasError && ( <p className="error-text">Name must not be empty.</p> )} </div> <div className={emailInputClasses}> <label htmlFor="name">Your E-Mail</label> <input type="email" id="email" onChange={emailChangeHandler} onBlur={emailBlurHandler} value={enteredEmail} /> {emailInputHasError && ( <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;