본문으로 건너뛰기

원티드 프리온보딩 과제 - 3일차

· 약 3분
arch-spatula

useInput

import { ChangeEvent, useState } from 'react';

function useInput<T>(inputGroup: T) {
const [inputValues, setInputValues] = useState(inputGroup);

const handleInputChange = (field: keyof T) => {
return (e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
setInputValues((prev) => ({
...prev,
[field]: e.target.value,
}));
};
};

const resetAllInput = () => {
const resetObject: { [key: string]: string } = {};
setInputValues((prev) => {
if (prev) {
Object.keys(prev).forEach((item) => {
resetObject[item] = '';
});
}

return prev;
});
};

const resetSpecificInput = (field: keyof T) => {
setInputValues((prev) => ({
...prev,
[field]: '',
}));
};

return { handleInputChange, inputValues, resetAllInput, resetSpecificInput };
}

export default useInput;

학원에서 포폴 만들 때 사용했던 custom hook을 개선했습니다.

import axios from 'axios';
import { useRef, useState } from 'react';
import { client } from '../api/client';
import { CustomButton, CustomInput } from '../components';
import { baseURL } from '../constants/constant';
import { useInput } from '../hooks';
import { checkEmail, checkPassword } from '../utils';

function Signup() {
const { inputValues, handleInputChange } = useInput<{
id: string;
pw: string;
}>({ id: '', pw: '' });

const idRef = useRef<HTMLInputElement>(null);

return (
<main className="flex h-screen flex-col items-center justify-center gap-4">
<div className="flex flex-col gap-4">
<CustomInput
value={inputValues.id}
placeholder="user@user.com"
onChange={handleInputChange('id')}
inputLabel={{ label: '아이디', id: '아이디' }}
errorMessage={idFeedback || checkEmail(inputValues.id)}
testId="email-input"
type="email"
customRef={idRef}
/>
<CustomInput
value={inputValues.pw}
placeholder="8자리 이상 입력해주십시오."
onChange={handleInputChange('pw')}
inputLabel={{ label: '비밀번호', id: '비밀번호' }}
errorMessage={checkPassword(inputValues.pw)}
testId="password-input"
type="password"
/>
</div>
</main>
);
}

export default Signup;
  • 이전과 다르게 typesafe하게 사용할 수 있게 되었습니다. 다시 자동완성 뽕맛에 취할 수 있습니다.

  • 여전히 아쉽습니다. 대입하는 인자로 알아서 타입 추론이 되게 만들고 싶었습니다. {id: "", pw: ""}만 대입해도 inputValues에 알아서 inputValues.id, inputValues.pw로 접근가능하게 작성하고 싶습니다. 호출하는 사람이 제네릭을 지정해야 한다는 점이 치명적인 단점입니다.

  • 지금도 타입스크립트 기초가 너무 안 되어 있습니다.

조건부 타입

input에 의존성 props를 만들고 싶었습니다. 일단 못찾았습니다.

<CustomInput value="adsf" onChange={(e) => {}} />
<CustomInput value="adsf" onChange={(e) => {}} label="label" id="id" />

원래는 이렇게 label을 지정 id도 같이 입력하게 만들고 싶었습니다.

이거에 오늘 3 ~ 4시간을 들였습니다.

<CustomInput value="adsf" onChange={(e) => {}} inputLabel={{ label: "비밀번호", id: "비밀번호" }} />
<CustomInput value="adsf" onChange={(e) => {}} />

그냥 이렇게 해결할 수 있었습니다.

@example

/**
* @example
* <CustomInput value="adsf" onChange={(e) => {}} />
* <CustomInput value="adsf" onChange={(e) => {}} inputLabel={{ label: "label", id: "id" }} />
*/

함수 hover하면 JSX 예시를 볼 수 있었습니다.