SimpleInput
์ปดํฌ๋ํธ๋ฅผ ์ดํด๋ณด๋ฉด, ์ฌ๊ธฐ์์ ์ ์ฒด ํผ์ด ์ ํจํ์ง ์๋์ง๋ฅผ ํ์ธํ ์ ์์ผ๋ฉด ๋ ์ข์ ๊ฒ ์ด๋ค.const [formIsValid, setFormIsValid] = useState(false);
formIsValid
์ํ(state)๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ด๋ค. ์ด๊ธฐ ๊ฐ์ false๋ก ์ง์ ํด๋๊ณ , formIsValid
์ํ์ ๊ฐ์ ํผ์ ์๋ input ๊ฐ์ด ๋ณํํ ๋๋ง๋ค ์
๋ฐ์ดํธ ๋๋๋ก ํด์ค๋ค. ๊ทธ๋ฆฌ๊ณ ์ด๋ฅผ ์ํด์ ๋ค์ useEffect
๋ฅผ ์ฌ์ฉํ ๊ฒ์ด๋ค.const enteredNameIsValid = enteredName.trim() !== "";
useEffect(() => {
if (enteredNameIsValid) {
}
}, [enteredNameIsValid]);
useEffect
๋ฅผ ํธ์ถํด์ ์ ์ฒด ํผ์ ์ ํจ์ฑ์ ์ค์ ํ๋ค. ์ด๋ฅผ ์ํด์๋ ํผ์ ์
๋ ฅ ๊ฐ์ ์ ํจ์ฑ์ด ํ์ํ๋ฏ๋ก, ํผ์ ์๋ ๋ชจ๋ ์
๋ ฅ ๊ฐ์ ์ ํจ์ฑ์ ์์กด์ฑ ๋ฐฐ์ด์ ์ถ๊ฐํ๋๋ก ํ๋ค.useEffect(() => {
if (enteredNameIsValid) {
setFormIsValid(true);
} else {
setFormIsValid(false);
}
}, [enteredNameIsValid]);
enteredNameIsValid
์ if
๋ฌธ์ ์ฌ์ฉํด์ ์ถ๊ฐํ๋ค. ๋ง์ฝ ํผ ์์ ์
๋ ฅ ๊ฐ์ด ๋๊ฐ๋ผ๋ฉด ์์กด์ฑ ๋ฐฐ์ด๊ณผ if ๋ฌธ ์์์ ๋ ๋ค๋ฅธ ์์ ๊ฐ์ ์ถ๊ฐํ๋ฉด ๋ ๊ฒ์ด๋ค. ์์ ๋ฐฐ์ ๋ ๋๋ก ์์กด์ฑ ๋ฐฐ์ด์ ๋ค์ด๊ฐ๋ ๊ฐ์ด ๋ฐ๋ ๋๋ง๋ค useEffect
๋ ๋ค์ ์คํ๋ ๊ฒ์ด๋ค. ๋ฐ๋ผ์ useEffect
ํธ์ถ์์๋ ๋ชจ๋ ์์กด์ฑ ๊ฐ๋ค์ ํฉ์น ๋ค์ ์ด ๊ฐ์ด ๋ชจ๋ ์ ํจํ์ง๋ฅผ ํ์ธํ๊ณ , ๋ง์ฝ ์
๋ ฅ ๊ฐ ๋ชจ๋๊ฐ ์ ํจํ๋ค๋ฉด ์ ์ฒด ํผ ๋ํ ์ ํจํ๋ค(setFormIsValid(true)
)๊ณ ์ค์ ํด์ค๋ค. ๊ทธ๋ฆฌ๊ณ ํ๋๋ผ๋ ์ ํจํ์ง ์๋ค๋ฉด, ์ ์ฒด ํผ ๋ํ ์ ํจํ์ง ์๋ค(setFormIsValid(false)
)๊ณ ์ค์ ํด์ค๋ค.formIsValid
์ํ(state)๋ฅผ ์ด์ฉํ ๋ฒํผ ๋นํ์ฑํformIsValid
์ํ๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ ๋์๋ค. ์๋ฅผ ๋ค๋ฉด, ๋ฒํผ์ formIsValid
์ ์ํ ๊ฐ์ ๋ฐ๋ผ ๋นํ์ฑํํ ์๋ ์์ ๊ฒ์ด๋ค.<button disabled={!formIsValid}>Submit</button>
formIsValid
์ด false ๋ผ๋ฉด(ํผ์ด ์ ํจํ์ง ์๋ค๋ฉด), ๋ฒํผ ํ๊ทธ์ disabled
๋ผ๋ ์์ฑ์ด ์๋๋ ์ ์๋๋ก ํ๋ค.button:disabled,
button:disabled:hover,
button:disabled:active {
background-color: #ccc;
color: #292929;
border-color: #ccc;
cursor: not-allowed;
}
disabled
๋์์ ๋์ ์คํ์ผ๋ง๋ ์ค์ ํด์ค๋ค.useEffect
๋ฅผ ๊ผญ ์ฌ์ฉํด์ผ๋ง ํ ๊น?useEffect(() => {
if (enteredNameIsValid) {
setFormIsValid(true);
} else {
setFormIsValid(false);
}
}, [enteredNameIsValid]);
effect
)๋ ์๊ธฐ ๋๋ฌธ์ useEffect
๋ฅผ ์ฌ์ฉํ ํ์๊ฐ ์๋ค๋ ๊ฑธ ์ ์ ์๋ค. ๋ํ useEffect
์์ด๋ ๊ทธ ์ด๋ค ๋ฌธ์ ๋ ๋ฐ์ํ์ง ์๋๋ค๋ ์ฌ์ค๋ ๋ง์ด๋ค.const enteredNameIsValid = enteredName.trim() !== "";
const nameInputIsInvalid = !enteredNameIsValid && enteredNameTouched;
useEffect
๋ด๋ถ์์ ์คํํ๊ณ ์๋ ํ ๋ก์ง๋ค์ ์์ enteredNameIsValid
๋ nameInputIsInvalid
์ ๊ฑฐ์ ๋์ผํ ๋ฐฉ๋ฒ์ผ๋ก ๊ฐ์ ์ป๊ณ ์๋ค. ์ฆ ์์ ํ ๊ฐ์ ์์
์ด๋ผ ๋งํ ์๋ ์๋๋ฐ, ๋ค๋ง useEffect
๋ด๋ถ์ ๋ก์ง๋ค์ ํผ ์ ์ฒด์ ๋ํ ๋ก์ง์ด๋ผ๋ ์ฐจ์ด๊ฐ ์์ ๋ฟ์ด๋ค. ๊ฒฐ๋ก ์ ์ผ๋ก ์ง๊ธ useEffect
๋ฅผ ์ฌ์ฉํ ์๋ ์์ง๋ง ์ด๋์ ์์ผ๋ฉฐ, ์ฌํ๊ฐ๋ฅผ ํ ๋ ์ถ๊ฐ์ ์ธ ์ปดํฌ๋ํธ๋ง ์๊ธธ ๋ฟ์ด๋ค. ๊ทธ๋ฆฌ๊ณ ์ด๋ ํ์คํ ์ํด์ด๋ค. ์ด๋ ๊ฒ ํ๋ ๋์ ์ฐ๋ฆฌ๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ผ๋ก ์ ๊ทผํ ์ ์๋ค.const [formIsValid, setFormIsValid] = useState(false);
useEffect(() => {
if (enteredNameIsValid) {
setFormIsValid(true);
} else {
setFormIsValid(false);
}
}, [enteredNameIsValid]);
formIsValid
์ํ(state)์ useEffect
๋ฅผ ์ ๊ฑฐํ๊ณ ,let formIsValid = false;
if (enteredNameIsValid) {
formIsValid = true;
} else {
formIsValid = false;
}
formIsValid
์ด๋ผ๋ ๋์ผํ ์ด๋ฆ์ ๋ณ์๋ฅผ ์ถ๊ฐํด์ ๊ธฐ๋ณธ๊ฐ์ false๋ก ๋ ๋ค, if
๋ฌธ ๋ด๋ถ์ ๋จ์ํ๊ฒ ์กฐ๊ฑด๋ฌธ์ด ์ฐธ์ด๋ฉด true๋ก ํ ๋นํ๊ณ , ์กฐ๊ฑด๋ฌธ์ด ๊ฑฐ์ง์ด๋ฉด false ๋ก ํ ๋นํ๋๋ก ์์
ํด์ฃผ์๋ค.let formIsValid = false;
if (enteredNameIsValid) {
formIsValid = true;
}
else
๋ฌธ๋ ํ์ ์๋ค. ๋ชจ๋ ๊ฐ์ด true ์ผ ๋์๋ง formIsValid
๋ณ์๊ฐ true ์ด๊ธฐ๋ง ํ๋ฉด ๋๊ธฐ ๋๋ฌธ์ด๋ค. ์ด์ ์ฝ๋๋ ๋์ผํ ๊ธฐ๋ฅ์ ์ํํ์ง๋ง ์ด์ ๋ณด๋ค ๊ฐ๊ฒฐํด์ก๊ณ useEffect
๋ฅผ ํตํ ์ธ๋ฐ ์๋ ๋ญ๋น๊ฐ ์ฌ๋ผ์ง๋ฉฐ ํ๊ฒฐ ๊ฐ๋ฒผ์์ก๋ค.const [enteredName, setEnteredName] = useState("");
const [enteredNameTouched, setEnteredNameTouched] = useState(false);
const [enteredEmail, setEnteredEmail] = useState("");
const [enteredEmailTouched, setEnteredEmailTouched] = useState(false);
const enteredNameIsValid = enteredName.trim() !== "";
const nameInputIsInvalid = !enteredNameIsValid && enteredNameTouched;
const enteredEmailIsValid =
enteredEmail.trim() !== "" && enteredEmail.includes("@");
const emailInputIsInvalid = !enteredEmailIsValid && enteredEmailTouched;
let formIsValid = false;
if (enteredNameIsValid && enteredEmailIsValid) {
formIsValid = true;
} else {
formIsValid = false;
}
const nameInputChangeHandler = (event) => {
setEnteredName(event.target.value);
};
const emailInputChangeHandler = (event) => {
setEnteredEmail(event.target.value);
};
const nameInputBlurHandler = () => {
setEnteredNameTouched(true);
};
const emailInputBlurHandler = () => {
setEnteredEmailTouched(true);
};
const formSubmitssionHandler = (event) => {
event.preventDefault();
setEnteredNameTouched(true);
setEnteredEmailTouched(true);
if (!enteredNameIsValid || !enteredEmailIsValid) {
return;
}
setEnteredName("");
setEnteredNameTouched(false);
setEnteredEmail("");
setEnteredEmailTouched(false);
};
const nameInputClasses = nameInputIsInvalid // true ์ด๋ฉด,
? "form-control invalid" // ๊ฒฝ๊ณ css
: "form-control";
const emailInputClasses = emailInputIsInvalid // true ์ด๋ฉด,
? "form-control invalid" // ๊ฒฝ๊ณ css
: "form-control";
SimpleInput
์ปดํฌ๋ํธ ์ฝ๋๋ฅผ ๋ณด๋ฉด, ์ ์์ ์ผ๋ก ์๋์ด ๋๊ณ ์์ง๋ง ์ค๋ณต๋๋ ๋ก์ง์ด ๋ง์ ๊ฑธ ์ ์๊ฐ ์๋ค. ๋ฌผ๋ก ์์ ์ด๋ฆ๊ณผ, ๋ก์ง์ ๋ํ
์ผ์ ๋ค๋ฅด์ง๋ง ์ ๋ฐ์ ์ธ ๋ก์ง์ ๊ตฌ์กฐ๋ ์ฌ์ค์ ์์ ํ ๊ฐ์ ๊ฒ์ด๋ ๋ค๋ฆ ์๊ธฐ ๋๋ฌธ์ด๋ค. ๋ง์ฝ ์ต์ ์ธ๊ฐ์ input์ด ์์ ๋ ์ต์ข
์ ์ผ๋ก๋ ๋๊ฐ์ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง ์ฝ๋๋ฅผ ์ธ ๋ฒ์ด๋ ๋ฐ๋ณตํด์ผ๋ง ํ ๊ฒ์ด๋ค. ๊ทธ๋ ๋ค๋ฉด, ์ด๋ฐ ์ค๋ณต๋ ์ฝ๋๋ค์ ์ด๋ป๊ฒ ํ๋ฉด ์ค์ผ ์ ์์๊น? ๋ฌผ๋ก , input ์ ๋ํ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค์ด์ ๊ด๋ จ๋ ๋ก์ง๋ค์ ๊ทธ ์ปดํฌ๋ํธ๋ก ๋ถ๋ฆฌํด์ ์ฌ์ฉํ ์ ์์ ๊ฒ์ด๋ค. ๊ทธ๋ฆฌ๊ณ ๊ทธ ์ปดํฌ๋ํธ ๋ง๋ค ์ ํจ์ฑ ๊ฒ์ฆ ๋ก์ง๊ณผ ์ํ(state)๋ฅผ ๋ฐ๋ก ๊ด๋ฆฌํด์ ์ฌ์ฉํ๋ฉด ๊ฝค ๊ด์ฐฎ์์ง๋ ๋ชจ๋ฅธ๋ค. ํ์ง๋ง ์ด๊ฒ๋ ์ปดํฌ๋ํธ๋ฅผ ๋ถ๋ฆฌํ์ ๋ฟ์ด์ง, ๋ณต์กํ ์ ์ฒด์ ์ธ ํผ์ ๊ด๋ฆฌํ๊ธฐ์๋ ์ด๋๊ฐ ์์ฐ์น ์๋ค.const useInput = () => {};
export default useInput;
hooks
ํด๋๋ฅผ ๋ง๋ค๊ณ , use-input.js
๋ผ๋ ํ์ผ์ ์์ฑํ๋ค. ์ด use-input.js
ํ์ผ์ ์ํ(state)๋ฅผ ๋ค๋ฃจ๋ ํ
๊ณผ input์ ๋ํ ๋ก์ง์ ๋ด์ ๊ฒ์ด๋ค. ํ์ผ ์์ useInput
์ด๋ผ๋ ํ
์ ๋ง๋ค๊ณ , ์ธ๋ถ์์ import ํด์ฌ ์ ์๋๋ก export ๋ ํด์ค๋ค. useInput
์ด๋ผ๋ ์ปค์คํ
ํ
์ ์ด์ฉํด์ input ๊ฐ๊ณผ input ์ฐฝ์ด touched ๋์๋์ง์ ๋ํ ์ํ๋ฅผ ๋ค๋ฃฐ ๊ฒ์ด๋ค. ๊ทธ๋ฆฌ๊ณ ์ด ๋์ ์กฐํฉํด ์ ํจ์ฑ ๋ํ ๊ฒ์ฆํ ๊ฒ์ด๋ค. ํด๋น ์ปค์คํ
ํ
์ ์ ์ฐํ๊ฒ ์๋ํ ์ ์์ด์ผ ํ๊ธฐ ๋๋ฌธ์, ์ธ๋ถ์์ ์ ํํ ๊ฒ์ฆ ๋ก์ง์ ์ปค์คํ
ํ
์์ ์ ๋ฌ ๋ฐ์ ์ ์๋๋ก ํด์ผ๋ง ํ๋ค.import { useState } from "react";
const useInput = () => {
const [enteredName, setEnteredName] = useState("");
const [enteredNameTouched, setEnteredNameTouched] = useState(false);
};
SimpleInput
์ปดํฌ๋ํธ์์ name
์ ๋ํ input ์ํ(state)๋ฅผ ๊ด๋ฆฌํด์ฃผ๋ ์ํ๋ค์ ๋ณต์ฌํด์ ๊ธ์ด์จ๋ค. ๊ทธ๋ฆฌ๊ณ ์ด ์ํ๋ค์ ์ ์ฐํ๊ฒ ์๋๋์ด์ผ ํ๊ธฐ ๋๋ฌธ์ ์กฐ๊ธ ๋ ํฌ๊ด์ ์ด๊ณ ์ผ๋ฐ์ ์ธ ์ด๋ฆ์ผ๋ก ์์ ํด์ค๋ค.const useInput = () => {
const [enteredValue, setEnteredValue] = useState("");
const [isTouched, setIsTouched] = useState(false);
// const enteredNameIsValid = enteredName.trim() !== "";
// const nameInputIsInvalid = !enteredNameIsValid && enteredNameTouched;
const valueIsValid = enteredName.trim() !== "";
const hasError = !valueIsValid && isTouched;
};
enteredNameIsValid
์ nameInputIsInvalid
๋ SimpleInput
์ปดํฌ๋ํธ์์ ๊ธ์ด์ ์ด์ ์ ๋ฐฉ์์ฒ๋ผ ์ผ๋ฐ์ ์ธ ์ด๋ฆ์ผ๋ก ์์ ํด์ค๋ค.const useInput = (validateValue) => {
const [enteredValue, setEnteredValue] = useState("");
const [isTouched, setIsTouched] = useState(false);
// const valueIsValid = enteredName.trim() !== "";
const valueIsValid = validateValue();
const hasError = !valueIsValid && isTouched;
};
valueIsValid
๊ฐ์ ๊ฒ์ฆ ๋ก์ง์ ๊ฒฝ์ฐ ํ๋ ์ฝ๋ฉ์ ์ง์ํด์ผ ํ๊ณ (์ธ๋ถ์ ์ปดํฌ๋ํธ์์ ์ ํจ์ฑ ๊ฒ์ฆ์ ๋ํ ์ ํํ ๋ก์ง์ ๋ฐ์์์ผ ํ๊ธฐ ๋๋ฌธ์.) ํ
์ด ์ฌ์ฉ๋๋ ๊ณณ์์ ์ด๋ค ๊ฒ์ฆ ๋ก์ง์ ์ฌ์ฉํ ์ง ๊ฐ์ ธ์์ผํ๊ธฐ ๋๋ฌธ์ useInput
์ปค์คํ
ํ
์์ validateValue
์ด๋ผ๋ ๋งค๊ฐ๋ณ์(ํจ์๊ฐ ๋ ๊ฒ์ด๋ค)๋ฅผ ๋ฐ์์ ํธ์ถํ๋๋ก ํ๋ค.const useInput = (validateValue) => {
const [enteredValue, setEnteredValue] = useState("");
const [isTouched, setIsTouched] = useState(false);
const valueIsValid = validateValue(validateValue);
const hasError = !valueIsValid && isTouched;
};
validateValue
ํจ์ ์์ enteredValue
๋ฅผ ์
๋ ฅํด ์คํํ ๊ฐ์ด ๋ ์ ์๋๋ก ์์ฑํด์ค๋ค.const useInput = (validateValue) => {
const [enteredValue, setEnteredValue] = useState("");
const [isTouched, setIsTouched] = useState(false);
const valueIsValid = validateValue(enteredValue);
const hasError = !valueIsValid && isTouched;
return {
value: enteredValue,
hasError: hasError, // hasError ํ๋๋ง ์จ๋ ๋๋ค.
};
};
useInput
์ปค์คํ
ํ
์ ๋ฌด์ธ๊ฐ๋ฅผ return(๋ฐํ) ํด์ค์ผ ํ๋๋ฐ, ์ด๋ ๊ฐ์ฒด๊ฐ ๋ ์๋ ๋ฐฐ์ด์ด ๋ ์๋ ์์์ ๊ธฐ์ตํ์. ์ด์จ๋ ํ์ฌ๋ ํ๋ ์ด์์ ๊ฐ์ ์ปค์คํ
ํ
์์ ๋ฐํํด์ผ ํ๊ธฐ ๋๋ฌธ์ ๊ฐ์ฒด๋ก ๋ฐํํ๋๋ก ํ๊ณ , ์ฌ๊ธฐ์ ๋ฐํํ๋ ๊ฐ์ฒด ์์๋ ๋ฐํํด์ผ ํ๋ ๊ฒ๋ค์ ์ด๋ฆ์ ํค, ๋ฐํํ๋ ๊ฐ๋ค์ ๊ฐ์ผ๋ก ๋ฃ๊ณ ์ธ๋ถ์์ ๊ทธ ํค ๊ฐ์ผ๋ก ์ ๊ทผํ ์ ์๋๋ก ํ๋ค. ๋ฌผ๋ก , ๊ฐ์ ์ด๋ฆ์ ํค์ ๊ฐ์ผ๋ก ์ฌ์ฉํ๋ค๋ฉด ๋ชจ๋ ์๋ฐ์คํฌ๋ฆฝํธ์ ๋ฌธ๋ฒ์ผ๋ก ํ ๋ฒ๋ง ์ฌ์ฉํด๋ ๋์ผํ ์๋์๋ฆฌ๋ก ๋ฐํ๋๋ค. ์ด์ ์ธ๋ถ์ ์ปดํฌ๋ํธ์์ ํด๋น ์ปค์คํ
ํ
์ setEnteredValue
์ setIsTouched
๋ฅผ ์ฌ์ฉํ ๋ฐฉ๋ฒ์ด ํ์ํ๋ค.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 nameInputChangeHandler = (event) => {
// setEnteredName(event.target.value);
// };
const valueChangeHandler = (event) => {
setEnteredValue(event.target.value);
};
// const nameInputBlurHandler = () => {
// setEnteredNameTouched(true);
// };
const inputBlurHandler = () => {
setIsTouched(true);
};
return {
value: enteredValue,
hasError: hasError,
};
};
SimpleInput
์ปดํฌ๋ํธ์์ ์ฌ์ฉํ๋ nameInputChangeHandler
์ nameInputBlurHandler
ํจ์๋ฅผ ๊ทธ๋๋ก ๊ธ์ด์ ๋ถ์ฌ ๋ฃ์ด์ค๋ค. SimpleInput
์ปดํฌ๋ํธ์์ ์ฌ์ฉํ๋ ์ํ ์
๋ฐ์ดํธ ํจ์์ ์ด๋ฆ์ ์ปค์คํ
ํ
์์ ๋ณ๊ฒฝ๋์๊ธฐ์ ์ด ๋ถ๋ถ๋ ์์ ํด์ค๋ค. ๊ทธ๋ฆฌ๊ณ ์ด์ ์ฒ๋ผ ์กฐ๊ธ ๋ ์ผ๋ฐ์ ์ธ ์ด๋ฆ valueChangeHandler
, inputBlurHandler
์ผ๋ก ์์ ํ๋ค.return {
value: enteredValue,
hasError: hasError,
valueChangeHandler: valueChangeHandler,
inputBlurHandler: inputBlurHandler,
};
useInput
์ปค์คํ
ํ
์ ์ฌ์ฉํ ์ปดํฌ๋ํธ์ธ SimpleInput
์ปดํฌ๋ํธ๋ก ์ด๋ํ์ฌ, import ํด์ค๋ค.import useInput from "../hooks/use-input";
const SimpleInput = (props) => {
const {} = useInput();
...
};
useInput
๋ฅผ ํธ์ถํ๊ณ , ์ด์ ๊ฐ์ฒด ๊ตฌ์กฐ ๋ถํด ํ ๋น์ ์ฌ์ฉํด์ ํด๋น ์ปค์คํ
ํ
์์ ๊ฐ์ฒด ํ์์ผ๋ก ๋ฐํ๋ ๊ฐ๋ค์ ์ถ์ถํ๋ค.const SimpleInput = (props) => {
const {
value: enteredName,
hasError: nameInputHasError,
valueChangeHandler: nameChangeHandler,
inputBlurHandler: nameBlurHandler,
} = useInput();
...
};
value
๋ ์ด๋ฆ์ผ๋ก ๋ฐํํ ๊ฐ์ enteredName
์ ํ ๋นํ๋ค. ๊ทธ๋ฆฌ๊ณ hasError
๋ nameInputHasError
๋ผ๋ ์ด๋ฆ์ผ๋ก ํ ๋นํ๋ค. (์ฌ๊ธฐ์ ๊ฐ์ผ๋ก ๋ค์ด๊ฐ๋ ์ด๋ฆ์ ์ฐ๋ฆฌ๊ฐ ์ฌ์ฉํ๋ ์ปดํฌ๋ํธ ๋ด๋ถ์์ ์ฌ์ฉํ๋ ๊ฒ์ด๋, ์ง๊ด์ ์ผ๋ก ๋ณด์ฌ์ง๋๋ก ์์ฑํด์ฃผ๋ฉด ๋ ์ข๋ค.) ๋๋จธ์ง ๋ฐํํ๋ ํจ์๋ค์ธ valueChangeHandler
์ inputBlurHandler
๋ ๊ฐ๊ฐ์ ์ฌ์ฉํ ์ด๋ฆ์ ์ง์ด์ ์
๋ ฅํด์ค๋ค.const SimpleInput = (props) => {
const {
value: enteredName,
hasError: nameInputHasError,
valueChangeHandler: nameChangeHandler,
inputBlurHandler: nameBlurHandler,
} = useInput();
...
};
useInput
์ปค์คํ
ํ
์์ ๋ฐ์์ค๊ธฐ๋ก ํ ๋งค๊ฐ๋ณ์๋ฅผ ๊ธฐ์ตํ ๊ฒ์ด๋ค. ์ธ๋ถ ์ปดํฌ๋ํธ์์ ํด๋น ์ปค์คํ
ํ
์ ์ฌ์ฉํ ๋ ์ด๋ค ๋งค๊ฐ๋ณ์๋ฅผ ๋๊ฒจ์ฃผ๊ธฐ๋ก ์ฝ์ํ์ผ๋, ์ด๋ฅผ ์์ฑํด๋ณด์.const useInput = (validateValue) => {
const [enteredValue, setEnteredValue] = useState("");
const [isTouched, setIsTouched] = useState(false);
const valueIsValid = validateValue(enteredValue);
const hasError = !valueIsValid && isTouched;
...
}
useInput()
์ปค์คํ
ํ
์ ํธ์ถํ๋ฉด์ ๋งค๊ฐ๋ณ์๋ฅผ ๋๊ฒจ์ฃผ๊ธฐ๋ก ํ๋ค. ๊ทธ๋ฆฌ๊ณ ์ด๋ฅผ ์ํด์ ์ฐ๋ฆฌ๋ ์ธ๋ผ์ธ ํจ์๋ฅผ ์ ์ํ ์ ์๋ค.const SimpleInput = (props) => {
const {
value: enteredName,
hasError: nameInputHasError,
valueChangeHandler: nameChangeHandler,
inputBlurHandler: nameBlurHandler,
} = useInput((value) => value.trim() !== "");
...
};
useInput
์ปค์คํ
ํ
์ ๋๊ฒจ์ฃผ๋ ๋งค๊ฐ๋ณ์์ value
๋ฅผ ์
๋ ฅ ๋ฐ์ ๋น ๋ฌธ์์ด์ ๋น๊ตํ ๊ฒฐ๊ณผ๋ฅผ ์ถ๋ ฅํ๋ value.trim() !== ""
์ ์ ์ํ์. ์ด๋ ํ์ดํ ํจ์๋ฅผ ์ฌ์ฉํด์ ๋งค๊ฐ๋ณ์๋ก ๋๊ฒจ์ค ๊ฒ์ธ๋ฐ, ์ด ์ปดํฌ๋ํธ์์๋ ์ธ๋ผ์ธ ํจ์๋ก ์ ์๋ง ๋๊ณ ์คํ๋์ง ์์ผ๋ฉฐ ๊ทธ์ useInput
์ ์ ๋ฌํ ๋ฟ์ด๋ค. ์ด๋ ์ปค์คํ
ํ
์ธ useInput
์์ ์ ๋ฌ ๋ฐ๊ธฐ๋ก ํ validateValue
๋งค๊ฐ๋ณ์๋ก ์ ํด์ง๊ณ ,import { useState } from "react";
const useInput = (validateValue) => {
const [enteredValue, setEnteredValue] = useState("");
...
const valueIsValid = validateValue(enteredValue);
...
};
useInput
์ปค์คํ
ํ
์ ๋ด๋ถ์ธ valueIsValid
๋ผ๋ ๋ณ์์ ๊ฐ์ผ๋ก ํ ๋นํ validateValue()
๊ฐ ํธ์ถ ๋์์ ๋ ๋น๋ก์ ์ธ๋ผ์ธ ํจ์๊ฐ ์คํ๋๋ค๋ ์๋ฏธ์ด๋ค. ๊ทธ๋ฆฌ๊ณ enteredValue
์ํ(state)๋ ํด๋น ์ปค์คํ
ํ
์์ ๋ค๋ฃจ๋ ์ํ์ด๊ธฐ ๋๋ฌธ์ validateValue()
๊ฐ ํธ์ถ๋์์ ๋ value
๊ฐ ๋์ด ์คํ๋๋ค.
์ฌ๊ธฐ์ ์๋ฏธํ๋
value
๋useInput((value) => value.trim() !== "")
์์ ์ธ๋ผ์ธ ํจ์๊ฐ ์ ๋ฌ๋ฐ์ ์ฒ๋ฆฌํ๋value
๋ฅผ ์๋ฏธํ๋ ๊ฒ์ด๋ค.
์ด๋ ๊ฒฐ๊ตญ ํจ์๋ฅผ ๋ค๋ฅธ ํจ์์ ์ ๋ ฅ ๊ฐ์ผ๋ก ๋ฃ๋ ์๋ฐ์คํฌ๋ฆฝํธ์ ๋ฌธ๋ฒ์ผ ๋ฟ์ด๋ค. ์ด๋ฅผ ํตํด์ ํด๋น ์ปค์คํ ํ ์ด ํ์ํ ์ปดํฌ๋ํธ๊ฐ ์ ํจ์ฑ ๊ฒ์ฆ ๋ก์ง์ ๋ฐ๊พธ๊ณ ๊ทธ ๊ฒ์ฆ ๋ก์ง์ ์ปค์คํ ํ ์์์ ์คํ๋ ์๊ฐ ์๋ ๊ฒ์ด๋ค. ์ ํจ์ฑ์ ๋ํ ์ ๋ณด ๋ํ ์ธ๋ถ ์ปดํฌ๋ํธ์์ ์ฌ์ฉ๋์ด์ผ ํ๊ธฐ ๋๋ฌธ์ ์ด ์ญ์ ๋ฐํํด์ฃผ๋๋ก ํ๋ค.
const useInput = (validateValue) => {
...
const valueIsValid = validateValue(enteredValue);
const hasError = !valueIsValid && isTouched;
...
return {
value: enteredValue,
isValid: valueIsValid,
hasError: hasError,
valueChangeHandler: valueChangeHandler,
inputBlurHandler: inputBlurHandler,
};
};
valueIsValid
๋ฅผ isValid
๋ผ๋ ์ด๋ฆ์ผ๋ก ๋ฐํํ๊ณ ,const SimpleInput = (props) => {
const {
value: enteredName,
isValid: enteredNameIsValid,
hasError: nameInputHasError,
valueChangeHandler: nameChangeHandler,
inputBlurHandler: nameBlurHandler,
reset: resetNameInput,
} = useInput((value) => value.trim() !== "");
// ์ํ ๋ก์ง
// const [enteredName, setEnteredName] = useState("");
// const [enteredNameTouched, setEnteredNameTouched] = useState(false);
// ์ ํจ์ฑ ๊ฒ์ฆ ๋ก์ง
// const enteredNameIsValid = enteredName.trim() !== "";
// const nameInputIsInvalid = !enteredNameIsValid && enteredNameTouched;
let formIsValid = false;
if (enteredNameIsValid && enteredEmailIsValid) {
formIsValid = true;
} else {
formIsValid = false;
}
// const nameInputChangeHandler = (event) => {
// setEnteredName(event.target.value);
// };
// const nameInputBlurHandler = () => {
// setEnteredNameTouched(true);
// };
};
SimpleInput
์ปดํฌ๋ํธ๋ก ๋์์์, isValid
๋ฅผ ์ถ์ถํ์ฌ enteredNameIsValid
๋ผ๋ ์ด๋ฆ์ผ๋ก ํ ๋นํ๋ค. ์ด๋ ๊ฒ ์์ ์ ํด์ฃผ๋ฉด, ํ์ฌ ์ปดํฌ๋ํธ์์ name ์ ๋ํ ์ํ(state)๋ฅผ ๊ด๋ฆฌํ๋ ๋ก์ง์ ์ ๋ถ ์ง์๋ ์ ์ฒด ํผ์ ์ ํจ์ฑ์ ๊ฒ์ฌํ๋ ์๋์ ๋ก์ง์์ enteredNameIsValid
๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ ๋๋ค. ๋ฌผ๋ก ๋๋จธ์ง nameInputChangeHandler
์ nameInputBlurHandler
ํจ์๋ ์ปค์คํ
ํ
์์ ์ฒ๋ฆฌํ๋ ๋ก์ง์ด๊ธฐ ๋๋ฌธ์ ๋ชจ๋ ์ง์์ค๋ค.<input
type="text"
id="name"
// onChange={nameInputChangeHandler}
// onBlur={nameInputBlurHandler}
onChange={nameChangeHandler}
onBlur={nameBlurHandler}
value={enteredName}
/>
input
ํ๊ทธ ์์ฑ์ ์ฐ๋ฆฌ๊ฐ ์ปค์คํ
ํ
์์ ๋ฐํํ ํจ์๋ค์ ์ถ์ถํ๋ฉด์ ์ด๋ฆ์ผ๋ก ์ง์ ํด์ฃผ์๋ nameChangeHandler
์ nameBlurHandler
ํจ์๋ฅผ ๊ฐ๊ฐ์ ์ด๋ฒคํธ ๊ฐ์ผ๋ก ํ ๋นํ๊ณ , value
๋ enteredName
์ผ๋ก ํ ๋นํ๋ค.// {
// nameInputIsInvalid && <p className="error-text">Name must not be empty.</p>;
// }
{
nameInputHasError && <p className="error-text">Name must not be empty.</p>;
}
nameInputIsInvalid
๋์ ์ฐ๋ฆฌ๊ฐ ์ปค์คํ
ํ
์์ ์ถ์ถํ nameInputHasError
๋ฅผ ๋์ ๋ฃ์ด์ค๋ค.const formSubmitssionHandler = (event) => {
event.preventDefault();
// setEnteredNameTouched(true);
// setEnteredEmailTouched(true);
if (!enteredNameIsValid || !enteredEmailIsValid) {
return;
}
setEnteredName("");
setEnteredNameTouched(false);
setEnteredEmail("");
setEnteredEmailTouched(false);
};
formSubmitssionHandler
๋ํ ์์ ์ด ํ์ํ๋ค. ํด๋น ํจ์์์๋ ์ํ(state)๋ฅผ ๋ณ๊ฒฝํด์ฃผ๊ณ , ํผ์ ์ด๊ธฐํ ํด์ฃผ๊ณ ์๋ค. ๋จผ์ , ์
๋ ฅ ๊ฐ์ด ์ ํจํ์ง ์๋ค๋ฉด ์ ์ถ ์กฐ์ฐจ ๋์ง ์๋๋ก ์ฐ๋ฆฌ๊ฐ ์ค์ ํด์ฃผ์๊ธฐ ๋๋ฌธ์ setEnteredNameTouched(true)
๋ setEnteredEmailTouched(true)
์ฒ๋ผ input ์ฐฝ์ ์ฌ์ฉ์๊ฐ ๊ฑด๋๋ ธ๋์ง์ ๋ํ ์ฌ๋ถ๋ฅผ ์ฒดํฌํ ํ์๊ฐ ์๊ธฐ์ ์ญ์ ํด์ค๋ค. ๊ทธ๋ฆฌ๊ณ ์๋์ ํผ์ ์ด๊ธฐํํด์ฃผ๋ ๋ก์ง ์ญ์ ๋ฐ๋ณต๋๊ณ ์์ผ๋ฏ๋ก ์ด ๋ถ๋ถ๋ ์ปค์คํ
ํ
์ ์์์์ฑ ํด์ฃผ๋ ๊ฒ ์ข๊ฒ ๋ค.const useInput = (validateValue) => {
const [enteredValue, setEnteredValue] = useState("");
const [isTouched, setIsTouched] = useState(false);
...
const reset = () => {
setEnteredValue("");
setIsTouched(false);
};
return {
value: enteredValue,
isValid: valueIsValid,
hasError: hasError,
valueChangeHandler: valueChangeHandler,
inputBlurHandler: inputBlurHandler,
reset: reset,
};
};
useInput
์ปค์คํ
ํ
์ผ๋ก ๋์์, ์ธ ๋ฒ์งธ ํจ์ reset()
์ ์ถ๊ฐํ๊ณ enteredValue
์ isTouched
๋ฅผ ์ด๊ธฐํ ํด์ค ๋ค, ํด๋น ํจ์๋ ๋์ผํ ์ด๋ฆ์ผ๋ก ๋ฐํํด์ค๋ค.const SimpleInput = (props) => {
const {
value: enteredName,
isValid: enteredNameIsValid,
hasError: nameInputHasError,
valueChangeHandler: nameChangeHandler,
inputBlurHandler: nameBlurHandler,
// โก๏ธ
reset: resetNameInput,
// โก๏ธ
} = useInput((value) => value.trim() !== "");
...
const formSubmitssionHandler = (event) => {
event.preventDefault();
if (!enteredNameIsValid || !enteredEmailIsValid) {
return;
}
// โก๏ธ
resetNameInput();
// โก๏ธ
setEnteredEmail("");
setEnteredEmailTouched(false);
};
};
SimpleInput
์ปดํฌ๋ํธ์์ ์ญ์๋ ์ด์ ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ํด๋น ์ปค์คํ
ํ
์์ ๋ฐํํ reset
ํจ์๋ฅผ resetNameInput
๋ผ๋ ์ด๋ฆ์ผ๋ก ํ ๋นํ๊ณ formSubmitssionHandler
ํผ ์ ์ถ ํจ์ ๋ด๋ถ์์ resetNameInput()
๋ฅผ ํธ์ถํด์ ์ด๊ธฐํํด์ค ์ ์๋๋ก ํ๋ค.const nameInputClasses = nameInputHasError // true ์ด๋ฉด,
? "form-control invalid" // ๊ฒฝ๊ณ css
: "form-control";
nameInputIsInvalid
๋์ ์ปค์คํ
ํ
์์ ๊ฐ์ ธ์จ nameInputHasError
๋ฅผ ๋์ฒดํ์ฌ ์์ ํด์ค๋ค.์ ์ฅํ๊ณ ์๋ก๊ณ ์นจํ๋ฉด, name input ์ฐฝ์ ์ด์ ๊ณผ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์๋ํ๊ณ , ์ ์ฒด ํผ์ ๋ํ ์ ํจ์ฑ ๊ฒ์ฆ ์ญ์ ์ ๊ณผ ๋์ผํ ๊ฒ์ ์ ์ ์๋ค.
๐จ ํด๋น ํฌ์คํ ์ Udemy์ โReact ์๋ฒฝ ๊ฐ์ด๋โ ๊ฐ์๋ฅผ ๋ฒ ์ด์ค๋ก ํ ๊ธฐ๋ก์ ๋๋ค.
โ๐ป ๊ฐ์ git repo ๋ฐ๋ก๊ฐ๊ธฐ