현인

Antd Modal 열릴 때 focus 처리 본문

기술 학습/React

Antd Modal 열릴 때 focus 처리

현인(Hyeon In) 2025. 1. 31. 11:40

검색 모달을 구현 중에 다음과 같은 요구사항이 주어졌다.

"모달 창이 열릴 때 검색 창에 자동으로 포커싱 되게 해주세요."

Ref로 Input Element를 참조하고 useEffect를 통해 초기 렌더링시 focus를 주면 될 것 같았다. 따라서 다음과 같이 코드를 작성했다

useEffect(() => {
    if (inputRef.current) {
      if (searchModalOpen) {
        inputRef.current.focus();
      }
    }
  }, [searchModalOpen]);

모달 창이 열리고, input에 focus가 잡혔다. 하지만 문제가 있었다. 모달 창을 닫고 다시 열면 focus가 잡히지 않았다. 무엇을 놓치고 있었을까 고민이 들었다. 스스로 유추한 문제점은 inputRef가 잡고 있는 reference와 렌더링되어 있는 input element가 다른 것 같았다.

유추한 문제점이 맞는지 Antd 공식 문서에서 Modal에 대해 좀 더 찾아보았다. Antd Modal은 destroyOnClose라는 속성을 사용해서 모달이 닫힐 때 컴포넌트를 unmount 할지를 결정할 수 있다. 해당 속성의 기본 값은 'false'다. 나 역시 별도로 설정해주지 않았기에, false로 설정되어 있을 것이다.

결론은 Modal 컴포넌트가 닫힐 때 unmount 되지 않았기에 inputRef가 참조하는 reference는 동일할 것이다. (콘솔로 찍어보니 같더라)

그럼 내가 유추했던 문제점은 틀렸고, 어디가 잘못된 것일까?

useEffect를 통해 searchModalOpen 값이 바뀔 때 focus를 실행했다. 이 부분을 곰곰히 생각해보니, searchModalOpen 값이 바뀌는 시점에 input 컴포넌트는 그려진(렌더링된) 상태일까 라는 생각이 들었다.

inputRef가 참조하는 input element는 변경되지 않지만, inputRef가 계속해서 참조하고 있지는 않을 것 같다는 생각이 들었다. 다시 말해 특정 순간에는 inputRef.current가 null 일 수도 있다는 것이다.

위에서 modal 컴포넌트는 닫아도 unmount 되지 않는다고 했으니, searchModalOpen 값이 false일 때는, modal의 visible 상태가 hidden 일 것이다. 그럼 serachModalOpen 값이 true로 바뀌면 hidden 상태가 풀리면서 다시 그려지게 될텐데 이 동안 inputRef는 input 컴포넌트가 그려지지 않았기 때문에 null 일 것이다. 나는 이 때 focus 메서드를 실행하게 된 것이고 당연히 아무일도 일어나지 않았다.

다시 정리 해보면

문제점: 모달 렌더링이 이루어지지 않은 상태에서 focus를 실행했기에 실행되지 않았다.

해결 방법: 모달 렌더링이 이루어진 이후에 focus를 실행한다.

이제 코드에 반영해보자.

useEffect를 통해 렌더링 이후 시점에 특정 메서드를 실행시키려면 setTimeout을 사용하면 된다.

useEffect(() => {
    if (inputRef) {
      if (searchModalOpen) {
        setTimeout(() => {
          inputRef.current?.focus();
        }, 0);
      }
    }
  }, [searchModalOpen]);

Antd Modal 공식 문서를 보면서 이슈를 찾다가 알게 된 사실이지만 useEffect로 focus를 잡을 필요가 없었다. 생각보다 Antd Modal은 많은 기능을 지원하더라. afterOpenChange 라는 속성을 활용하면 Modal 창이 열리고 난 이후에 처리할 함수를 넘길 수 있다..ㅎㅎ

따라서 useEffect를 지우고 Modal에 afterOpenChange 속성을 활용했다.

<Modal
      open={searchModalOpen}
      onCancel={handleSearchModalCancel}
      afterOpenChange={(open) => {
        if (open) {
          inputRef.current?.focus();
        }
      }}
>

처음부터 공식문서를 잘 살펴보고 개발했으면 이런 과정을 안 겪었을텐데, 습관대로 개발하다가 이런 문제가 생기는 것 같다. 글로 정리해서 보니까 별로 고민 안한거 같지만 막상 개발할 때는 꽤나 머리 아팠다.

그래도 여러가지 배워가는 것 같아서 좋은 경험했다고 생각한다!

반응형

'기술 학습 > React' 카테고리의 다른 글

[React Hooks] useEffect 사용법  (0) 2023.08.30
[React Hooks] useState 사용법  (0) 2023.08.30