민스씨의 일취일장

TIssue | Flutter | onPressed 메서드 무한 호출 이슈 본문

Mobile/Flutter & Dart

TIssue | Flutter | onPressed 메서드 무한 호출 이슈

읻민스 2025. 8. 17. 19:11
반응형

onPressed에 지정된 메서드가 무한 호출되는 이슈에 대한 원인 분석과 해결책에 대한 글이다.

Flutter - onPressed 메서드 무한 호출 이슈

TIssue - Flutter onPressed 메서드 무한 호출 이슈 썸네일 이미지이다.
TIssue - Flutter onPressed 메서드 무한 호출 이슈

현상

TextButton의 onPressed 속성에 상태값에 따라 호출되는 메서드를 다르게 구성해 놓았는데, 실행시 해당 메서드가 무한으로 호출되는 이슈가 발생하였다.

원인 1 - 빌드 과정에서 실행됨

TextButton(
  onPressed: widget.isDetailOn
      ? widget.onTapDeatilShow()
      : widget.onTapSummaryShow(),
  ...
)

TextButton이 빌드 되는 과정에서 위의 삼항연산자를 평가하기 위해 코드를 실행하게 된다. 따라서 빌드 과정에서 widget.onTapDetailShow()와 widget.onTapSummaryShow() 모두가 실행된다. 하지만 이 두 메서드는 각각 isDetailOn 상태값을 반대로 바꾸기 때문에, 매번 상태가 변경되어 무한 호출이 발생하켜 버린 것이다.

원인 2 - 클로저 미사용

onPressed에 메서드를 넘길 때, 2가지 방식이 있다. 괄호 없이 함수의 이름만 작성하거나, 괄호를 포함하는 것이다. 괄호 없이 함수의 이름만 작성하는 것은 함수가 인자를 필요로 하지 않을 경우에만 가능하고, 이 경우는 함수의 참조값을 넘긴 것으로 볼 수 있다. 따라서 나중에 실행되어도 해당 참조값인 메서드가 실행될 수 있다. 그런데 문제는 괄호가 있는 경우 있다. 인자가 있는 경우 괄호를 사용할 수 밖에 없는데, 이렇게 괄호를 포함해서 작성하면 빌드과정에서 해당 메서드를 실행시켜 실행결과값을 onPressed에 할당해 버린다. (즉, 인자가 없더라도 괄호를 사용한다면 함수의 결과값이 할당된다.)

따라서 onPressed에는 함수의 참조값을 전달하던지, 함수가 실행된 결과가 전달하고자 하는 함수가 되도록 하면 된다.

해결책 - 클로저 사용

이 때 사용할 수 있는 방식이 closure이다. 클로저는 자기 주변(lexical scope)를 묶어(close)서 가지고 있는 함수이다. 따라서 필요한 값들까지 포함해서 함수로 할당할 수 있는 방식이라고 할 수 있다. 사용법은 간단한데, 빈 메서드로 전달하고자 하는 메서드를 감싸면 된다.

TextButton(
  onPressed: () {
  	widget.isDetailOn
      ? widget.onTapDeatilShow()
      : widget.onTapSummaryShow(),
  }
  ...
)

이 내용을 바탕으로 좀 더 단단하게 표현할 수도 있다. 

TextButton(
  onPressed: widget.isDetailOn
      ? () => widget.onTapDeatilShow()
      : () => widget.onTapSummaryShow(),
  ...
)

단지 빈메서드로 감싼 모습을 하고 있지 않아, 클로저가 적용된 것인지 혼동할 수 있다. 따라서 위 형태가 클로저를 적용했다는 것에 익숙해질 필요가 있다.

728x90
반응형