웹사이트를 만드는데 Form은 로그인, 회원가입 등등 여러 곳에서 사용된다.
따라서 Form 컴포넌트는 공통 컴포넌트이므로 Form 컴포넌트를 인터페이스로 분리할 필요성이 있다!
자세한 설명이 궁금하다면 Github 링크를 통해 확인하길 바란다.
Form은 기본적으로 아래 두 가지가 필요하다.
이 때 Form이 모든 입력창의 값이 유효성을 통과하는지를 border 테두리로 보여주고, Button은 모든 입력창의 값이 유효성을 통과할 시 활성화된다고 하자.
Form의 User Flow은 아래와 같다,
위의 Flow를 통해 우리는 Form 컴포넌트에서 각 입력창의 유효성검증을 위한 정규표현식과, Submit한 후 수행할 작업들이 필요하다는 것을 확인할 수 있다.
따라서 Form 컴포넌트에서 Input Field Data와 Submit Callback을 주입함으로써 Form 컴포넌트를 선언적으로 사용할 수 있다.
export default function Form({ fieldData, submitCallback }) {
let isSubmit = true;
const inputValues = {};
const FormInputs = fieldData.map((data, idx) => {
const { name, placeholder, type, regex } = data;
const [value, setValue] = useState('');
inputValues[name] = value;
const isValidated = value !== '' && validator(value, regex);
isSubmit &&= isValidated;
return (
<S.Input
key={idx}
name={name}
placeholder={placeholder}
type={type}
value={value}
onChange={({ target: { value } }) => setValue(value)}
validated={(value === '' || isValidated).toString()}
/>
);
});
const submitHandler = e => {
e.preventDefault();
submitCallback(isSubmit, inputValues);
};
return (
<>
<S.InputWrap>{FormInputs}</S.InputWrap>
<S.Button disabled={!isSubmit} onClick={submitHandler}>
로그인
</S.Button>
</>
);
}
위의 codesandbox에서 Login페이지에서 Form 컴포넌트를 사용하였다.
// src/constants/fieldData
// Login Form Field 데이터 전달
export const loginField = [
{
name: 'email',
placeholder: '전화번호, 사용자 이름 또는 이메일',
type: 'text',
regex: REGEX_EMAIL,
},
{
name: 'password',
placeholder: '비밀번호',
type: 'password',
regex: REGEX_PW,
},
];
// src/hook/useAuth
// Login Callback 전달
export function useAuth() {
const navigate = useNavigate();
const dispatch = useUserDispatch();
const loginCallback = getLoginCallback(navigate, dispatch);
const logoutCallback = getLogoutCallback(navigate, dispatch);
return { loginCallback, logoutCallback };
}
const getLoginCallback =
(navigate, dispatch) => async (isValid, inputValues) => {
if (!isValid) return;
const registerUserList = await getRegisterUserList();
const isUserExist = await checkIsUserExist(
inputValues,
registerUserList,
);
if (!isUserExist) {
alert('아이디 또는 비밀번호를 잘못 입력하셨습니다!');
return;
}
dispatch({
type: 'LOGIN',
userId: extractIdFromEmail(inputValues.email),
});
alert('로그인 성공하였습니다.');
navigate('/', { replace: true });
};
const getLogoutCallback = (navigate, dispatch) => async () => {
alert('로그아웃 되었습니다.');
dispatch({
type: 'LOGOUT',
});
navigate('/login', { replace: true });
};
// src/page/Login
export default function Login() {
const { token } = useUserState();
return (
<>
{token && <Navigate to="/" replace={true} />}
<BackGround>
<S.Container>
<LoginFormLayout />
</S.Container>
</BackGround>
</>
);
}
Form을 사용하는 LoginForm에는 Input Field를 만들 loginField와 submit후 수행할 loginCallback을 전달받는다.
Login Form 컴포넌트를 만들어줄 필요 없이, Field Data와 Submit Callback을 전달하기만 하면 되므로 선언적이다는 장점이 있다.