En Flutter, entender la diferencia entre StatelessWidget y StatefulWidget es fundamental para construir aplicaciones eficientes. Cada tipo tiene su propósito específico y elegir el correcto impacta directamente en el rendimiento.
Un StatelessWidget es inmutable. Una vez creado, no puede cambiar su estado interno. Es perfecto para UI estática que no necesita actualizarse.
class MiTextoEstatico extends StatelessWidget {
final String texto;
const MiTextoEstatico({Key? key, required this.texto}) : super(key: key);
Widget build(BuildContext context) {
return Text(
texto,
style: TextStyle(fontSize: 18),
);
}
} Un StatefulWidget puede cambiar su estado interno durante su ciclo de vida. Ideal para UI dinámica que responde a interacciones del usuario.
class Contador extends StatefulWidget {
_ContadorState createState() => _ContadorState();
}
class _ContadorState extends State<Contador> {
int _numero = 0;
void _incrementar() {
setState(() {
_numero++;
});
}
Widget build(BuildContext context) {
return Column(
children: [
Text('Contador: $_numero'),
ElevatedButton(
onPressed: _incrementar,
child: Text('Incrementar'),
),
],
);
}
} Regla de oro: Si no necesitas cambiar datos, usa StatelessWidget. Si necesitas actualizar la UI, usa StatefulWidget.
// Perfecto para StatelessWidget
class TarjetaPerfil extends StatelessWidget {
final String nombre;
final String email;
const TarjetaPerfil({Key? key, required this.nombre, required this.email})
: super(key: key);
Widget build(BuildContext context) {
return Card(
child: ListTile(
leading: Icon(Icons.person),
title: Text(nombre),
subtitle: Text(email),
),
);
}
} // Necesita StatefulWidget
class FormularioLogin extends StatefulWidget {
_FormularioLoginState createState() => _FormularioLoginState();
}
class _FormularioLoginState extends State<FormularioLogin> {
final _emailController = TextEditingController();
bool _cargando = false;
void _iniciarSesion() {
setState(() {
_cargando = true;
});
// Lógica de login...
}
Widget build(BuildContext context) {
return Column(
children: [
TextField(
controller: _emailController,
decoration: InputDecoration(labelText: 'Email'),
),
ElevatedButton(
onPressed: _cargando ? null : _iniciarSesion,
child: _cargando
? CircularProgressIndicator()
: Text('Iniciar Sesión'),
),
],
);
}
void dispose() {
_emailController.dispose();
super.dispose();
}
} Combinando ambos tipos para máxima eficiencia:
// StatefulWidget para la lista (datos cambian)
class ListaTareas extends StatefulWidget {
_ListaTareasState createState() => _ListaTareasState();
}
class _ListaTareasState extends State<ListaTareas> {
List<String> _tareas = ['Estudiar Flutter', 'Hacer ejercicio'];
void _agregarTarea(String tarea) {
setState(() {
_tareas.add(tarea);
});
}
Widget build(BuildContext context) {
return ListView.builder(
itemCount: _tareas.length,
itemBuilder: (context, index) {
// StatelessWidget para cada item (no cambia individualmente)
return TareaItem(tarea: _tareas[index]);
},
);
}
}
// StatelessWidget para items individuales
class TareaItem extends StatelessWidget {
final String tarea;
const TareaItem({Key? key, required this.tarea}) : super(key: key);
Widget build(BuildContext context) {
return ListTile(
leading: Icon(Icons.check_box_outline_blank),
title: Text(tarea),
);
}
} // ✅ Correcto: Widget estático extraído
class PantallaContador extends StatefulWidget {
_PantallaContadorState createState() => _PantallaContadorState();
}
class _PantallaContadorState extends State<PantallaContador> {
int _contador = 0;
Widget build(BuildContext context) {
return Scaffold(
appBar: const BarraSuperiorEstatica(), // StatelessWidget
body: Column(
children: [
Text('Contador: $_contador'), // Solo esto cambia
const TextoEstatico(), // StatelessWidget
],
),
floatingActionButton: FloatingActionButton(
onPressed: () => setState(() => _contador++),
child: Icon(Icons.add),
),
);
}
}
class BarraSuperiorEstatica extends StatelessWidget {
const BarraSuperiorEstatica({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return AppBar(title: Text('Mi App'));
}
} // Incorrecto: Todo en StatefulWidget innecesariamente
class PantallaContador extends StatefulWidget {
_PantallaContadorState createState() => _PantallaContadorState();
}
class _PantallaContadorState extends State<PantallaContador> {
int _contador = 0;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Mi App')), // Se re-renderiza innecesariamente
body: Column(
children: [
Text('Contador: $_contador'),
Text('Texto que nunca cambia'), // Se re-renderiza innecesariamente
],
),
);
}
} StatelessWidget: Para UI que no cambia. Más rápido y simple. StatefulWidget: Para UI dinámica que responde a cambios. Más potente pero complejo.