Menu
CoddyTech

Cargar una vez en initState

Parte de la sección Datos y red del Journey de Flutter de Coddy. Lección 7 de 27.

Flutter vuelve a llamar a build cada vez que se vuelve a dibujar la pantalla: después de cada setState, cuando gira el teléfono, cuando cambia un elemento principal. Esto puede ocurrir muchas veces por segundo. build solo debe describir la pantalla, nunca iniciar tareas.

Por eso, un fetch escrito dentro de build se ejecuta de nuevo en cada redibujado. Cada ejecución es una nueva solicitud al servidor, y la pantalla puede mostrar una respuesta distinta cuando nadie la ha pedido:

// una nueva solicitud en cada redibujado
FutureBuilder<String>(
  future: fetch('/tip'),
  ...
)

Crea el futuro una sola vez, cuando se abre la pantalla, en initState, y dale a FutureBuilder ese mismo futuro cada vez:

late Future<String> _tip;

@override
void initState() {
  super.initState();
  _tip = fetch('/tip');
}

initState se ejecuta una vez, antes del primer build. Inícialo con super.initState();, tal como lo pide Flutter.

challenge icon

Desafío

Intermedio

Toca el corazón en la barra superior: el consejo cambia porque fetch está en build. Carga el consejo una sola vez:

  • añade late Future<String> _tip; al estado
  • asígnale un valor en initState con fetch('/tip')
  • pasa _tip a FutureBuilder

Pruébalo tú mismo

import 'package:flutter/material.dart';

import 'api.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: TipScreen(),
    );
  }
}

class TipScreen extends StatefulWidget {
  const TipScreen({super.key});

  @override
  State<TipScreen> createState() => _TipScreenState();
}

class _TipScreenState extends State<TipScreen> {
  bool liked = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Tip of the Day'),
        actions: [
          IconButton(
            icon: Icon(liked ? Icons.favorite : Icons.favorite_border),
            onPressed: () {
              setState(() {
                liked = !liked;
              });
            },
          ),
        ],
      ),
      body: Center(
        child: Padding(
          padding: const EdgeInsets.all(24),
          child: FutureBuilder<String>(
              future: fetch('/tip'),
              builder: (context, snapshot) {
                if (snapshot.hasData) {
                  return Text(
                    snapshot.data!,
                    textAlign: TextAlign.center,
                    style: const TextStyle(fontSize: 24),
                  );
                }
                return const CircularProgressIndicator();
              },
            ),
        ),
      ),
    );
  }
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Datos y red

Practica por tu cuenta: Compilador de Flutter online