Saltar al contenido
第02話Episodio 02

Apuntes

Cosas cortas que me habría gustado saber antes. Numeradas por si las quieres citar.

052

Sin Equatable, BLoC reconstruye aunque el estado sea igual

· bloc · 1 min

BLoC decide si reconstruir comparando el estado nuevo con el viejo. Si tu estado no implementa igualdad por valor, dos instancias con los mismos datos son distintas y la UI se repinta al pedo.

class OrderData extends OrderState with EquatableMixin {
  final List<Order> orders;
  const OrderData(this.orders);

  @override
  List<Object?> get props => [orders];
}

Con props, dos OrderData con la misma lista son iguales y BLoC no reconstruye. Sin eso, cada emit es un rebuild garantizado. En Dart 3 también puedes usar records o clases con == generado; el punto es que la igualdad sea por valor, no por identidad.

051

connectivity_plus dice "hay wifi", no "hay internet"

· flutter · 1 min

connectivity_plus te dice si el dispositivo está conectado a una red, no si esa red llega a tu servidor. Un wifi de aeropuerto con portal cautivo reporta wifi y no navega.

Úsalo como señal para intentar sincronizar, no como prueba de que va a funcionar. La verdad la da el request:

final result = await Connectivity().checkConnectivity();
if (result != ConnectivityResult.none) {
  await _tryDrain(); // que este maneje su propio fallo
}

Si tratas “hay red” como “el POST va a salir bien”, vuelves a tener el bug que la cola offline venía a resolver.

050

Un índice en SQLite por cada columna del WHERE

· sqlite · 1 min

Si consultas la outbox por status = 'pending' en cada drenado y esa columna no tiene índice, SQLite recorre la tabla entera. Con miles de filas, se nota.

CREATE INDEX idx_outbox_status ON outbox(status);

Regla: toda columna que aparezca en un WHERE o un ORDER BY frecuente merece un índice. El coste es algo de escritura y espacio; la ganancia en lectura es de orden de magnitud.

049

if-case: desestructurar y comprobar en una línea

· dart · 1 min

Cuando solo te interesa un caso de un sealed o un tipo, no montes un switch entero. if-case comprueba el patrón y extrae el dato de una vez.

if (response case Success(:final data)) {
  render(data);
}

Equivale a comprobar is Success y luego acceder a .data, pero sin el cast intermedio ni la variable extra. Si no coincide, el bloque no entra.

048

switch expression en vez de la cadena de if-else

· dart · 1 min

Desde Dart 3, switch es una expresión: devuelve un valor. Adiós a la variable mutable que ibas rellenando en cada if.

final label = switch (status) {
  Status.active => 'Activo',
  Status.paused => 'En pausa',
  Status.done => 'Terminado',
};

Si status es un enum o un sealed, el compilador exige que cubras todos los casos. Un if-else no te obliga a nada y deja huecos silenciosos.

047

BlocSelector en vez de BlocBuilder

· bloc · 1 min

Si tu widget solo depende de un campo del estado, BlocBuilder lo reconstruye cada vez que cambia cualquier otro campo. BlocSelector te deja suscribirte a una sola porción.

BlocSelector<CartBloc, CartState, int>(
  selector: (state) => state.items.length,
  builder: (context, count) => Badge(count: count),
)

El widget solo se reconstruye cuando cambia el número de items, no cuando cambia el total, el cupón o el estado de carga.

046

Migrar el esquema de SQLite sin borrar la base

· sqlite · 1 min

onUpgrade recibe la versión antigua y la nueva. El error habitual es escribir un if por versión; lo correcto es una cascada sin else, para que un usuario que salta de la v1 a la v4 ejecute las tres migraciones en orden.

onUpgrade: (db, oldVersion, newVersion) async {
  if (oldVersion < 2) await db.execute('ALTER TABLE orders ADD COLUMN synced INTEGER DEFAULT 0');
  if (oldVersion < 3) await db.execute('CREATE INDEX idx_synced ON orders(synced)');
}
045

Remote Config como interruptor de funciones

· firebase · 1 min

Publicar en Play Store tarda horas y la revisión puede tardar días. Si una función nueva sale mal, no quieres depender de un release para apagarla.

Envuelve cada función nueva en un booleano de Remote Config con fetchAndActivate al arrancar y un valor por defecto seguro en local. Si algo se rompe en producción, lo apagas desde la consola en un minuto.

044

const en widgets: cuándo importa de verdad

· dart · 1 min

const en un widget no acelera el pintado: evita que Flutter cree una instancia nueva y, sobre todo, permite que el algoritmo de reconciliación descarte el subárbol por identidad.

Importa cuando el widget está dentro de algo que se reconstruye a menudo. En una pantalla estática no cambia nada medible, así que no llenes el código de const por costumbre: ponlo donde haya reconstrucciones.