이러한 과정들을 거치고 나니
StateLogin.jsx 파일의 코드는
좀더 간결해졌습니다
그렇지만 솔직히 말하자면
여기에 작성해야 했던 코드 대부분이
입력값과 didEdit 상태를 관리하는 것에 초점이 맞추어져 있었고
handleInputChange와 handleInputBlur 함수를 이용해
해당 상태를 업데이트하기 위한 것들이었습니다
그러므로 우리는 이 코드를 외부로 의탁하여
재사용하기를 원합니다
그러기 위해서는 어떻게 해야 할까요?
커스텀 훅의 도움을 받으면 됩니다
커스텀 훅은 우리가 의탁하기 원하는
코드의 상태를 관리하기 위해 필요하기 때문에
일반적인 함수를 사용할 수는 없습니다
커스텀 훅을 구축하기 위해서
src(소스) 폴더 아래에 hooks 폴더를 추가하겠습니다
배우셨듯이, 이름은 여러분에게 달려있기에
꼭 hooks라고 이름짓지 않아도 됩니다
그리고 이 안에 useInput.js 파일을 만들어 줍니다
이 파일이 JSX일 필요가 없는 이유는
이 안에 JSX 코드를 작성하지 않을 것이기 때문입니다
이제 여기에 useInput 함수를 내보내는데
앞서 커스텀 훅 섹션에서 배우셨던 것과 같이
이렇게 use로 시작되어야만
리액트가 이것을 훅 함수로 인식하고
훅의 규칙이 적용됩니다
이어서 이 상태 관리 코드를 가져다가
useInput에 복사해 넣겠습니다
물론 약간의 수정을 해주기는 해야 합니다만
여기에서 제가 의도하는 바는
양식에 있는 각각의 입력 요소에 한번씩 사용될
useInput 훅을 구축하는 것이기 때문입니다
만약 두개의 입력 요소가 있다면
훅의 호출 횟수 또한 두 번인 것입니다
즉 다수의 입력값을 묶어주는
객체 상태를 관리하는 대신
저는 여기에서 하나의 값에 대한 관리만을 하고자 합니다
그렇기 때문에 해당 상태를
enteredValues에서 enteredValue로 이름을 바꾸어 주겠습니다
초기값은 외부에서 설정이 가능해야 하는데
해당 입력에 우리가 원하는 값을
사전에 넣어둘 수 있도록 하기 위해서입니다
우리는 여기 커스텀 훅 안에서
기본값의 매개변수를 받아
이것을 이용해 enteredValue 상태의
기본 상태를 설정할 수 있습니다
그리고 리액트에서 useState를 가져오면
이렇게 하나의 상태가 됩니다
didEdit의 경우 여러 입력의 상태를 결합하는
객체를 관리하는 대신
단 하나의 값을 관리하게 됩니다
저는 우선 False로 해두고 시작해볼텐데
설정이 가능하도록 만들고 싶다면
여기 이것을 매개변수로 받을 수도 있습니다
이제 상태가 있으니
해당 상태를 업데이트해줄 함수를
커스텀 훅으로 가져와야 하기 때문에
handleInputChange와 handleInputBlur를 복사해서
여기에 있는 제 커스텀 훅에 추가해 넣도록 하겠습니다
이제 우리가 관리하는 것은 여기에 있는
하나의 입력과 하나의 값이기 때문에
여기에 있는 함수를 단순화할 수 있습니다
예를 들어
handleInputChange에서 이벤트 객체를
얻게 될 것이라 기대하고
setEnteredValue에는
event.target.value를 적어 넣습니다
setDidEdit는 False로 설정해 주는데
이는 우리가 여기에서 관리하는 것이
하나의 입력값이기 때문입니다
handleInputBlur에서는 setDidEdit를 True로 설정해 줍니다
이제 커스텀 훅은 보다 단순한 코드가 되었습니다
이렇게 상태와 더불어
이러한 함수를 가지고 있는 것만으로는 아무런 소용이 없습니다
우리는 이 훅이 사용될 컴포넌트에
이것을 노출시켜 주어야 합니다
그러므로 여기에 커스텀 훅의 값을 반환해 주는데
여러 값을 묶어주기 위해서
배열을 리턴시킬 수도 있지만
저는 객체를 반환하겠습니다
여기에 값을 반환시키고
우리가 관리하는 enteredValue 상태를 입력해준 뒤
반환된 객체에 있는
값 속성을 통해 노출시키도록 하겠습니다
더불어 이 반환된 오브젝트에
handleInputChange와 handleInputBlur에 포인터를 추가해서
해당 오브젝트가 가진 이러한 속성에
여기 함수를 가리키는 값이 속해있도록 하겠습니다
didEdit의 경우 아직 사용되지 않고 있지만
곧 달라지게 될 것입니다
제가 당장 바꾸고자 하는 부분은 여기에 있는 식별자인데
이것은 더이상 handleInputBlur에서 받지 않습니다
이것으로 우리는 이 useInput 훅의
초안을 갖게 되었고 이를 사용할 수 있게 되었습니다
이를 위해 저는 StateLogin.jsx 파일로 돌아가서
거기에 있는 이 상태 부분을 삭제하고
이어서 handleInputChange와 handleInputBlur 또한 지우고
여기에 주석화해서 지운 함수도 지워서
코드를 더 가볍게 만들어 주겠습니다
대신 useInput을 호출하고
hooks 폴더에 있는 useInput.js 파일로부터
useInput을 가져오겠습니다
useState를 가져오는 부분도 이제 삭제해 주는데
이 컴포넌트에서 더이상
커스텀 상태의 관리를 하지 않기 때문입니다
대신 우리에게는 useInput이 있는데
useInput은 해당 입력에 속해있는
defaultValue를 원합니다
여기에 저는 비어있는 문자열을 전달해서
구조 분해(Destructure) 할 수 있는 객체를 돌려받는데
그 객체의 값에
별칭을 배정하겠습니다
그리고 이것을 emailValue라고 이름 붙일텐데
제가 각각 다른 입력에 useInput을 여러번 사용할 계획을
가지고 있기 때문입니다
그렇기에 여기 별칭을 두어
이 값이 무엇인지를 명확히 알 수 있도록 해야 합니다
또 handleInputChange를 가져와서
handleEmailChange라는 별칭을 붙여주고
handleInputBlue를 가져와서
handleEmailBlur라는 별칭을 붙여주는 식으로
커스텀 훅을 이렇게 사용하도록 하겠습니다
이제 여기에 있는 유효성 검증 로직은 작동하지 않지만
이메일 입력의 값 속성으로
emailValue를 배정할 수 있게 되었습니다
여기 onBlur에서는 식별자의 효용성이 사라졌기에
더이상 감싸는 요소를 필요로 하지 않습니다
이 훅은 하나의 입력 상태만을 관리하기 위해 존재하므로
해당 작업을 전담하는 handleEmailChange 펑션이
있기 때문입니다
이에 따라 여기 아래에 있는 코드는 단순화되어
handleEmailBlur를 가리키고
이 또한 handleEmailChange를 가리키도록 하면 됩니다
이렇게 바뀌어도 해당 작업은 그대로 작동하는데
useInput 훅에 들어가있는
이 InputChange 함수는
기본 이벤트 객체만을 필요로 하고
정확히 그것이 우리가 여기에서
onChange 속성 값으로 이것을 한데 묶을 때 얻게 되는 것입니다
언급된 바와 같이 유효성 검증이 문제가 될 수 있는데
다행히 이것 또한
커스텀 훅에 의탁할 수 있습니다
여기에 새로운 계산형 값을 추가하고
이를 valueIsValid라고 하겠습니다
그리고 유효성 검사 함수를 기반으로
해당 값의 유효성을 검증하게 되는데
이때 값을 직접 코딩하여 훅에 넣으면 안됩니다
이 훅은 각각 다른 필요조건과 검증 기능을 가진
다양한 입력에 사용되어야
하기 때문입니다
그러므로 유효성 검증 함수를 이 훅 함수에서
두 번째 인수로 받아들이는 것이 타당한데
이렇게 validationFn을 호출해
이 훅에서 관리하고 있는
enteredValue를 전달해서
valueIsValid를 계산하기 위함입니다
그래야만 이 훅의 외부
말하자면 우리가 훅을 사용하는
Login 함수 같은 곳에서
그저 검사 로직과
함수가 무엇인지를 정의해주고
그 로직을 훅 안에서 실행할 수 있게 되는 것입니다
이번에는 여기 valueIsValid를 사용해서
return에 또다른 값인 hasError를 추가해 주는데
이것은 didEdit과 !valueIsValid를
이렇게 결합한 것입니다
상태 관리에 사용되고 있는
입력이 만약 수정되어 didEdit이 True고
해당 값이 유효하지 않다면, hasError는 True가 됩니다
그리고 이 변화는 우리로 하여금
실행되어야 할 유효성 함수를
useInput에 전달할 수 있도록 해 줍니다
예를 들자면 useInput에 isEmail을 포인터로 전달하여
이것이 검사 함수로 실행되도록 하는 것과 같습니다
그리고 여기 있는 이메일 검증 코드는 지울 수 있게 됩니다
많은 검사 함수ㅡㄹㄹ 작동시키고 싶은 경우에는
여기 로직을 수정해서
함수 배열을 받아들여
해당 배열에 담긴 모든 함수를 실행하도록 하거나
여기 로직을 바꾸는 방법이 있습니다
useInput의 두 번째 인수로 설정한 부분인데
검사 함수를 가리키게 하는 대신
익명의 함수를 전달해서
그것으로 하여금
이 검사 함수 매개변수의 값이 되도록 해서
여기에서 실행되도록 하는 것입니다
이 익명의 함수에는
값이 생기는 것을 기대할 수 있는데
이것은 제가 방금 말했듯이
훅의 안에서 이 함수가 실행될 것이고
enteredValue가
이 함수에 값으로 전달될 것이기에
우리는 여기에서 값을 기대할 수 있게 되는 것입니다
이후에는 해당 값의 유효성 검증을 위해
작동시키고자 하는 모든 코드를 작동시키고
모두 마친 뒤에 True 혹은 False를 반환하면 됩니다
그리고는 여기에 isEmail과
isNotEmpty를 넣어줍니다
이렇게 여러 개의 함수를 수월하게 실행시킬 수 있습니다
이 코드 또한 더 짧게 만들 수 있는데
return문을 삭제하고
중괄호와 세미콜론을 모두 없애준 뒤
useInput을 이렇게 사용해 주면 됩니다
그리고 두 번째 입력인 패스워드에
이것과 동일한 접근법을 반복해주면 되는데
초기 값으로는 비어있는 문자열이 있습니다
여기에 있는 hasMinLength의 경우에는
MinLength 매개변수 설정을 위해
실행되는 방식에 대한
완전한 제어가 필요한 함수입니다
다시 감싸는 함수 안에
값을 넣어 전해주고
이것이 훅 안에서 호출되었을 때
hasMinLength를 호출해서
값을 전달하면서
두 번째 매개변수를 6으로 설정해 줍니다
이제 이러한 값을 모두 여기에 추출할 수 있고
구조 분해를 사용해서 값을 가져오는데
이 경우 passwordValue가 되겠고
handleInputChange를 가져와서
이것을 handlePasswordChange라고 이름붙이고
handleBlur도 가져와서
이렇게 handlePasswordBlur라고 이름 붙이겠습니다
그리고 여기에 hasError를 추출해
passwordHasError라고 이름 붙이겠습니다
이메일에 속한 첫 번째 입력에도
같은 작업을 해주겠습니다
여기에서도 hasError를 추출하는데
이것은 emailHasError라고 이름을 바꿔주겠습니다
이제 여기에 있는 패스워드 검사 상수를
삭제할 수 있게 되었습니다
양식으로 내려가면
이메일 입력의 error 속성에
emailHasError에 대한 검사를 넣고
이것이 True일 경우 이 오류 메시지가 전달되도록 하겠습니다
onChange의 입력은
이제 handlePasswordChange가 되고
onBlur에서는 handlePasswordBlur가 되고
value에서는 passwordValue가 되고
error의 경우
passwordHasError 상수가 되는 것입니다
이렇게 이 코드는 또다시 좀더 쉬워졌고
이 위쪽의 많은 코드를 삭제했는데
로직을 커스텀 훅에 넣었기에 가능한 일이었습니다
여기에 있는 handleSubmit에서는
이제 emailHasError 또는 passwordHasError를 검사할 수 있게 되었는데
여기에 return을 넣어
유효하지 않은 입력이 들어왔을 때
로직이 이어서 실행되지 않도록 할 수 있습니다
만약 유효한 입력이 들어왔다면
여기에 emailValue와 passwordValue를 출력해서
잠재적으로는
해당 정보를 백엔드로 보낼 수 있습니다
이것을 모두 마쳤다면
여기에는 커스텀 훅인 useInput 훅이 사용되고 있습니다
이제 다시 작업하던 양식으로 돌아가보면
이전과 같이 작동하는 것을 볼 수 있는데
앞서 보여드렸던 이 유효성 검증 과정이
이제는 커스텀 훅의 도움을 받아
각각의 상태를 기록하고
입력값이 얻어지는 것을 볼 수 있습니다