textfield 4글자 작성 후 자동 tab

유림·2023년 7월 18일
0

REACT

목록 보기
11/16
post-thumbnail

textfield 4글자 작성 후 자동 tab

개발 중 기존 쿠폰 등록하는 부분의 UI 수정과 함께 플로우도 수정되며 새로 작성한 코드가 있어 기록해두고자한다
기존엔 쿠폰함에 가면 바로 쿠폰번호를 등록했다면
수정 후 플로우
: 버튼 선택 -> 쿠폰등록 dialog 오픈 -> 번호 작성 및 확인 -> 등록, 에러처리 등 작업을 하게되었다

그 중 총 4개씩 총 16개의 숫자로 구성된 쿠폰번호를 작성하는데 기획서에 있던 것은 아니지만 작성하 때 더 편한 UI로 개선하기 위해 4글자가 되면 자동으로 tab기능이 이뤄지도록 구현했다 (뿌듯😋)

hook의 watch도 써보고 onChange도 써봤지만 useRef가 가장 간결하게 만들 수 있었다.
사실 처음엔 useState에 focus의 true, false값을 제어하는 형태로 진행하다가 포커스 이동 시 재랜더로 인한 불필요한 동작들이 추가되어 useRef로 구현했다.. 확실히 더 개발하다보면 state를 최대한 적게쓰면서 작성하는 tip이 필요하다 더 연구해봐야지!

  • 혹시 아래 코드로 진행할 때 타입에러가 있다면 useRef의 'HTMLInputElement'을 any로 바꿔서 타입 외 코드는 작동이 가능한지 확인한 후 본인의 코드에 맞는 타입을 추가줘도 된다
const inputRefs = [useRef<HTMLInputElement>(), useRef<HTMLInputElement>(), useRef<HTMLInputElement>(), useRef<HTMLInputElement>()];

  // 작성 후 다음 textfield로 포커스 이동시키기
  const handleInputChange = (name: string) => {
    const nextFieldName = `num${Number(name.charAt(3)) + 1}`;
    if (getValues(name).length >= 4) {
      inputRefs.map((e: any, i: number) => {
        if (nextFieldName === `num${i + 1}` && inputRefs[i].current) {
          inputRefs[i].current.focus();
        }
      });
    }
  };


-> return쪽 코드


<Stack direction={'row'} sx={{ flex: 1, pt: '2px', p: pxToRem(20), gap: 1 }}>
   {inputRefs.map((e: any, i: number) => {
       return (
		<CTextField
            key={`cpn-${i}`}
            name={`num${i + 1}`}
            label=""
            variant="outlined"
            className={'InquiryTextArea'} // style이 같아서 사용
            help={false}
            maxLength={4}
            sx={{ maxHeight: 40}}
            inputRef={inputRefs[`${i}`]}
            resizeType={'none'}
			onChangeCallback={() => handleInputChange('num' + `${i + 1}`)}
                    />
                  );
                })}
              </Stack>

**dialog 오픈 시 첫번째 CTextField만 focus상태로 오픈되게 만들기 위해 아래 코드를 추가하여 덧붙인다

그냥 추가하면 아마 focus가 안될 것이다ㅜ
dialog의 렌더가 끝난 후 적용해야하기 때문이다.
복잡한 코드는 아니지만 랜더 시점에 따라 다른 부분들이 있어서 시점을 고려하여 구현할 필요가 있다

  // Dialog 렌더링이 완료 후 적용 가능
  useEffect(() => {
    if (openRegister) {
      setTimeout(() => {
        inputRefs[0].current && inputRefs[0].current.focus();
      }, 0);
    }
  }, [openRegister]);
profile
ɪ ʜᴏᴘᴇ ᴛᴏ sᴏʟᴠᴇ ʀᴇᴀʟ ᴘʀᴏʙʟᴇᴍs👩🏻‍💻❤️

1개의 댓글

comment-user-thumbnail
2023년 7월 18일

아주 유용한 정보네요!

답글 달기