리팩토링 3. 사용자 입력 컴포넌트 개선

Gn0lee·2023년 1월 1일
0

Tech 이모저모

목록 보기
11/18

서비스에서 사용자는 많은 정보들을 입력해야한다. 아이디, 비밀번호, 이메일 기타등등.. 그리고 각 입력값들은 제한조건들이 존재한다. 예를 들면 이메일 양식은 영어와 @의 조합으로 구성되어야 한다던가 비밀번호에 특수문자가 포함되어 있을 수 있다. 제한조건을 만족하지 않는 경우 textinput에 에러 메세지를 표시해 주어야 한다.

리팩토링 진행 전에는 email state가 변경됨에 따라 emailValidation state를 갱신하는 방식으로 구현하였다. useEffect의 dependency에 email을 추가하여 email의 정규검사 결과에 따라 emailValidation state를 변경하는 방식이었다.

하지만 입력받는 정보의 종류가 많으면 state 개수가 많아진다. 따라서 컴포넌트 내에 useEffect 관련 코드의 양이 급격하게 늘어나고 유지보수 및 코드 파악이 더욱 어려워졌다. 이와 같은 문제를 나는 useReducer 훅을 이용하여 사용자 입력 state를 컴포넌트 파일에서 분리시켰다. 그 결과 useEffect를 굳이 사용하지 않아도 되었으며 컴포넌트 내에 비즈니스 로직 코드가 외부 파일로 이동하여 유지보수나 코드 파악이 한결 수월하였다.

useReducer 사용법은 훅 이름답게 redux 사용법과 아주 유사하다.


const formReducer = (state, action) => {
  switch (action.type) {
    case "INPUT_EMAIL":
      return {
        ...state,
        email: action.value,
        isEmailValid: action.value.includes("@"),
      };
    case "INPUT_PASSWORD":
      return {
        ...state,
        password: action.value,
        isPasswordValid: action.value.trim().length > 6,
      };
    case "BLUR_EMAIL":
      return {
        ...state,
        email: state.email,
        isEmailValid: state.email.includes("@"),
      };
    case "BLUR_PASSWORD":
      return {
        ...state,
        password: state.password,
      };
    default:
      break;
  }
};

const Login = (props) => {
  const [formState, dispatchForm] = useReducer(formReducer, {
    email: "",
    isEmailValid: undefined,
    password: "",
    isPasswordValid: undefined,
  });

  const emailChangeHandler = (event) => {
    dispatchForm({ type: "INPUT_EMAIL", value: event.target.value });
  };

  const passwordChangeHandler = (event) => {
    dispatchForm({ type: "INPUT_PASSWORD", value: event.target.value });
  };

  const validateEmailHandler = () => {
    dispatchForm({ type: "BLUR_EMAIL" });
  };

  const validatePasswordHandler = () => {
    dispatchForm({ type: "BLUR_PASSWORD" });
  };
  
  ...
};

위와 같이 reducer 함수를 만들어서 useReducer 훅의 첫번째 변수에 할당한다. 위의 예제에서는 reducer 함수를 한 파일에서 선언하였지만 나는 context 디렉토리 내에 login.reducer.ts 파일을 만들어서 따로 관리하였다.

useReducer를 사용할 경우 한 입력 값이 다른 입력값의 상태에 영향을 줄때 매우 편리하였다. 기존 useState를 사용했다면 useEffect를 사용해야만 했을 것이다.(아니면 state를 객체 형태로 선언하여 사용했을 것이다.) 하지만 useReducer의 경우 하나의 state로 관리하여 매우 편리하다.

생각보다 사용자 입력이 굉장히 귀찮고 까다로웠다. 단순히 로그인의 경우 아이디와 비밀번호면 충분하지만 우리 회사 제품의 경우 입력받아야할 정보가 굉장히 많았다. 그래서 컴포넌트 내 비즈니스 로직 코드가 굉장히 많았고 구현 방식도 가지 각색이었다. 리팩토링 기간동안 이를 하나로 통일하는 것이 쉬운 작업은 아니었다. 하지만 하나로 통일하고 나니 수정사항이 발생해도 빠르게 대처할 수 있었다.

profile
정보보다는 경험을 공유하는 테크 블로그입니다.

0개의 댓글