초보 개발자의 성장 일기

로그인 입력폼이 유효하지 않을 때 본문

Development/React JS

로그인 입력폼이 유효하지 않을 때

YUNA 2024. 1. 9. 00:14

로그인 폼을 구현하다가 사용자가 로그인할 때 입력폼에 아무것도 입력되지 않으면

 

  • 로그인 버튼을 비활성화를 해야할지
  • 입력 폼에 focus를 주어야 할지

고민이 들었다.

 

 

입력을 안했을 때 버튼 자체가 비활성화가 되는것도 좋지만,

로그인 버튼을 눌렀을 때 어떤 입력폼에 입력을 해야할지 focus를 주면 사용자 입장에서 더 편리할 수도 있겠다는 생각이 들었다.

 

무엇을 입력해야 하는지 알 수 있고,

focus를 주면 사용자가 바로 입력하기 편리할 것 같다는 생각이 들었다.

 

 

1. focus를 줄 수 있는 activate 함수 만들기

const Input = (props) => {
  const inputRef = useRef();
 
  const activate = () => {
    inputRef.current.focus();
  };
 
  return (
    <div
      className={`${classes.control} ${
        props.isValid === false ? classes.invalid : ""
      }`}
    >
      <label htmlFor={props.id}>{props.label}</label>
      <input
        ref={inputRef}
        type={props.type}
        id={props.id}
        value={props.value}
        onChange={props.onChange}
        onBlur={props.onBlur}
      />
    </div>
  );
};
 
 

 

email과 password는 각각 재사용이 가능한 Input 컴포넌트로 관리되어 있다.

이 컴포넌트 안에 focus를 줄 수 있는 activate 함수를 만들었다.

 

const emailInputRef = useRef();
const passwordInputRef = useRef();

  const submitHandler = (event=> {
    event.preventDefault();
    if (formIsValid) {
      authCtx.onLogin(emailState.value, passwordState.value);
    } else if (!emailIsValid) {
      emailInputRef.current.activate();
    } else {
      passwordInputRef.current.activate();
    }
  };
 
 

 

submitHandler 함수, 즉 로그인 버튼을 눌렀을 때 실행될 함수에 email 또는 password가 유효하지 않을 때를 구분해서 activate함수가 실행될 수 있게 해 주었다. 

 

오류 메시지

하지만 이렇게 하면 오류를 직면하게 된다.

함수컴포넌트는 ref를 받을 수 없다고 한다.

props 객체에서 ref프롭을 받아드리지 못하는 것이다.

 

이 문제를 해결하기 위한 훅이 있다.

 

 

2. useImperativeHandle 사용

import { useImperativeHandle } from "react";
 

 

react 내장 훅인 useImperativeHandle을 사용하는 것이다.

이 훅을 사용하면 컴포넌트나 컴포넌트 내부에서 오는 기능을 명령적으로 사용할 수 있게 해준다.

 

일반적인 state 프롭 관리를 통하지 않고

부모 컴포넌트의 state를 통해 컴포넌트를 제어하지 않고

프로그래밍적으로 컴포넌트에서 무언가를 직접 호출하거나 조작해서 사용하게 해 준다.

 

그래서 이 훅은 자주 사용하지 않는것이 좋다고 한다.

 

 

사용 방법은

  useImperativeHandle(ref, () => {
    return {
      focus: activate,
    };
  });
 

 

1) 첫번째 매개변수에는 Input 매개변수로 props와 ref를 인수로 받아온다.

ref를 외부에서 설정해야 하는 경우 이것을 설정했다는 것을 확실히 하기 위해

부모 컴포넌트에는 ref 프롭을 추가하고 바인딩하면 ref로 받아와서 연결을 해 준다.

 

🔍 바인딩이란?

HTML에 원하는 데이터를 일치하게 만드는 것이다.

 

ref를 props와 같이 받아오면서 바인딩을 해 주는 것이다.

이 ref를 천번째 매개변수로 넣어준다.

 

2) 두번째 매개변수에는 함수를 넣어 준다.

이 함수는 외부에서 사용할 수 있는 모든 데이터를 포함한 객체를 반환해야 한다.

외부에서 접근할 수 있어야 하는 것을 가리킨다.

 

const Input = React.forwordRef((props, ref) => {
 

 

두번째 인수 ref를 활성화 시키기위해서 React.forwardRef로 감싸주어야 한다.

(react를 import해야 사용할 수 있다.)

Input은 ref에 바인딩 될 수 있는 리액트 컴포넌트가 된다.

 

  const submitHandler = (event=> {
    event.preventDefault();
    if (formIsValid) {
      authCtx.onLogin(emailState.value, passwordState.value);
    } else if (!emailIsValid) {
     emailInputRef.current.focus();
    } else {
     passwordInputRef.current.focus();
    }
  };
 
 

 

이전에 작성해 주었던 함수에서 activatefocus로 바꿔준다. 

 

 

이렇게 하면 email input값이 비어있거나 유효하지 않을 때 로그인 버튼을 누르면 email input에 포커스가 맞춰지고

password가 비어있거나 유효하지 않을 때는 password input에 포커스가 맞춰진다.