Yeda AI Tips · #108

English

Verifica context.mounted después de cada await

Tu app de Flutter se cae después de una llamada de red lenta. Una línea lo arregla. El patrón siempre es el mismo: un handler de botón hace await de una petición, el usuario navega a otra pantalla mientras está en vuelo, y cuando la respuesta por fin llega tu código toca un BuildContext cuyo widget ya no existe. Con una conexión rápida nunca lo ves; con un round trip celular de 3 segundos es un reporte de crash.

Por qué muere el contexto

El BuildContext de cada widget solo es válido mientras ese widget está montado en el árbol. Un await es una brecha asíncrona: entre la línea anterior y la posterior puede pasar cualquier cosa — el usuario hace pop de la ruta, el padre se reconstruye sin este hijo, la app pasa a segundo plano. Si el widget fue descartado durante la brecha, llamar Navigator.of(context), ScaffoldMessenger.of(context) o setState después golpea un elemento difunto. La documentación del framework es directa: acceder a propiedades de un BuildContext o llamar sus métodos "solo es válido mientras mounted es true".

La guarda de una línea

Desde Flutter 3.7, el propio BuildContext expone una propiedad mounted, así que el arreglo es una sola verificación entre el await y el primer uso del contexto:

Future<void> _onSave(BuildContext context) async {
  await repository.save(item);        // async gap — anything can happen here
  if (!context.mounted) return;       // the guard
  Navigator.of(context).pop();        // now safe
  ScaffoldMessenger.of(context)
      .showSnackBar(const SnackBar(content: Text('Saved')));
}

Dentro de una subclase de State, usa el mounted propio del estado — la misma idea, sin parámetro de contexto:

final data = await api.fetch();
if (!mounted) return;
setState(() => _data = data);

La guarda va después de cada await que preceda un uso del contexto — con dos awaits seguidos, la primera verificación ya está obsoleta cuando el segundo termina.

Reglas prácticas

SituaciónGuarda
Función normal que recibe un BuildContextif (!context.mounted) return; después de cada await
Dentro de State<T> (tiene su propio contexto)if (!mounted) return; después de cada await
Varios awaits antes de usar el contextoVerifica después del último await, no solo del primero
Contexto capturado antes del await (p. ej. final nav = Navigator.of(context) primero)Capturar Navigator/ScaffoldMessenger antes de la brecha evita el lookup, pero igual verifica mounted antes de tocar la UI
No hay uso del contexto después del awaitNo hace falta guarda

Deja que el linter lo atrape por ti

No dependas de la disciplina. La regla del linter de Dart use_build_context_synchronously marca exactamente este bug: un BuildContext referenciado a través de una brecha asíncrona sin verificación de mounted. Es una regla estable y forma parte del set recomendado flutter_lints, que los proyectos nuevos de Flutter (2.3.0+) incluyen por defecto vía analysis_options.yaml:

include: package:flutter_lints/flutter.yaml

Si tu CI corre flutter analyze, esta clase de crash se convierte en un fallo de build en lugar de un incidente en producción.

Notas para usuarios avanzados

Recursos

Read this article in English

¿Construyendo una funcionalidad con IA? Yeda AI diseña, audita y entrega sistemas LLM de producción.

Habla con nosotros · Lee el blog