`use_build_context_synchronously` 린트 규칙: 비동기 간격에서의 BuildContext 사용

use_build_context_synchronously 린트 규칙: 비동기 간격에서의 BuildContext 사용

use_build_context_synchronously비동기 간격(asynchronous gap)을 지나서 BuildContext를 사용할 때 Dart 분석기가 알려주는 린트 규칙이에요. Flutter 위젯 코드에서 매우 흔하게 접하는 실수를 막아 주는 규칙이에요.

출처: use_build_context_synchronously

본문

설명

비동기 간격을 지나서 BuildContext를 사용하지 마세요. BuildContext를 나중에 쓰려고 저장해 두면 진단하기 어려운 크래시로 쉽게 이어질 수 있어요. 비동기 간격은 BuildContext를 슬쩍 저장해 두는 셈이라서, 코드를 쓸 때 가장 놓치기 쉬운 부분 중 하나예요.

BuildContext를 사용할 때는 비동기 간격 이후에 mounted 속성을 확인해야 해요. 확인할 대상은 BuildContext에 어떻게 접근했는지에 따라 달라져요.

  • Statecontext 속성을 사용할 때는 Statemounted 속성을 확인해야 해요.
  • 다른 BuildContext 인스턴스(지역 변수나 함수 인자 같은 것)를 사용할 때는 BuildContextmounted 속성을 확인해야 해요.

BAD:

void onButtonTapped(BuildContext context) async {
  await Future.delayed(const Duration(seconds: 1));
  Navigator.of(context).pop();
}

await로 비동기 간격을 지난 뒤에 context를 쓰고 있어요. 이 사이에 위젯이 화면에서 사라지면 크래시가 날 수 있어요.

GOOD:

void onButtonTapped(BuildContext context) {
  Navigator.of(context).pop();
}

비동기 간격이 없으면 그냥 사용해도 돼요.

void onButtonTapped(BuildContext context) async {
  await Future.delayed(const Duration(seconds: 1));

  if (!context.mounted) return;
  Navigator.of(context).pop();
}

비동기 이후에 context.mounted를 확인한 뒤에만 사용해요. BuildContextmounted 속성을 쓰는 예시예요.

abstract class MyState extends State<MyWidget> {
  void foo() async {
    await Future.delayed(const Duration(seconds: 1));
    if (!mounted) return; // Checks `this.mounted`, not `context.mounted`.
    Navigator.of(context).pop();
  }
}

State 안이라면 this.mounted(간단히 mounted)를 확인해요. 주석에도 있듯이 여기서는 context.mounted가 아니라 this.mounted를 검사해요.

활성화하기

use_build_context_synchronously 규칙을 켜려면 analysis_options.yaml 파일의 linter > rulesuse_build_context_synchronously를 추가해요.

linter:
  rules:
    - use_build_context_synchronously

YAML 맵 문법을 쓴다면 linter > rules 아래에 use_build_context_synchronously: true를 넣으면 돼요.

linter:
  rules:
    use_build_context_synchronously: true

더 알아보기