userInput 커스텀 훅
userInput custom hooks
import { useState } from "react";
const useInput = (validateValue) => {
const [enteredValue, setEnteredValue] = useState("");
const [isTouched, setIsTouched] = useState(false);
const valueIsValid = validateValue(enteredValue);
const hasError = !valueIsValid && 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;
Usecase 1
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 {
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);
// nameInputRef.current.value = ''; => NOT IDEAL, DON'T MANIPULATE THE DOM
resetNameInput();
resetEmailInput();
};
const nameInputClasses = nameInputHasError
? "form-control invalid"
: "form-control";
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={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={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;
Usecase 2
import useInput from "../hooks/use-input";
const isNotEmpty = (value) => value.trim() !== "";
const isEmail = (value) => value.includes("@");
const BasicForm = (props) => {
const {
value: firstNameValue,
isValid: firstNameIsValid,
hasError: firstNameHasError,
valueChangeHandler: firstNameChangeHandler,
inputBlurHandler: firstNameBlurHandler,
reset: resetFirstName,
} = useInput(isNotEmpty);
const {
value: lastNameValue,
isValid: lastNameIsValid,
hasError: lastNameHasError,
valueChangeHandler: lastNameChangeHandler,
inputBlurHandler: lastNameBlurHandler,
reset: resetLastName,
} = useInput(isNotEmpty);
const {
value: emailValue,
isValid: emailIsValid,
hasError: emailHasError,
valueChangeHandler: emailChangeHandler,
inputBlurHandler: emailBlurHandler,
reset: resetEmail,
} = useInput(isEmail);
let formIsValid = false;
if (firstNameIsValid && lastNameIsValid && emailIsValid) {
formIsValid = true;
}
const submitHandler = (event) => {
event.preventDefault();
if (!formIsValid) {
return;
}
console.log("Submitted!");
console.log(firstNameValue, lastNameValue, emailValue);
resetFirstName();
resetLastName();
resetEmail();
};
const firstNameClasses = firstNameHasError
? "form-control invalid"
: "form-control";
const lastNameClasses = lastNameHasError
? "form-control invalid"
: "form-control";
const emailClasses = emailHasError ? "form-control invalid" : "form-control";
return (
<form onSubmit={submitHandler}>
<div className="control-group">
<div className={firstNameClasses}>
<label htmlFor="name">First Name</label>
<input
type="text"
id="name"
value={firstNameValue}
onChange={firstNameChangeHandler}
onBlur={firstNameBlurHandler}
/>
{firstNameHasError && (
<p className="error-text">Please enter a first name.</p>
)}
</div>
<div className={lastNameClasses}>
<label htmlFor="name">Last Name</label>
<input
type="text"
id="name"
value={lastNameValue}
onChange={lastNameChangeHandler}
onBlur={lastNameBlurHandler}
/>
{lastNameHasError && (
<p className="error-text">Please enter a last name.</p>
)}
</div>
</div>
<div className={emailClasses}>
<label htmlFor="name">E-Mail Address</label>
<input
type="text"
id="name"
value={emailValue}
onChange={emailChangeHandler}
onBlur={emailBlurHandler}
/>
{emailHasError && (
<p className="error-text">Please enter a valid email address.</p>
)}
</div>
<div className="form-actions">
<button disabled={!formIsValid}>Submit</button>
</div>
</form>
);
};
export default BasicForm;
Conclusion
신기한 패턴이다. Stateless Component일 때는 위의 컴포넌트를 활용하자.