CodeBlanks Logo Icon CodeBlanks

Summary - setState

Combine setState and lifting to build a counter screen.

Summary - setState

In this section you learned three things: setState marks a State dirty and reruns build on the next frame; with lifting state up you move state to the common parent of siblings and pass callbacks to children; with the mounted check you safely call setState after async work.

if (mounted) {
  setState(() { _count++; });
}

Keep state as small as possible and check mounted after every async wait.

Practice Counter screen: setState + lifting + mounted

In the SayacEkrani stateful widget, hold _sayac and _durum. The _artir and _azalt methods should change _sayac with setState. The async _durumYukle method waits 100 ms and sets _durum to 'hazır' with if (mounted). In initState, call print('başlangıç: $_sayac') and start _durumYukle. The Gosterici stateless widget should take deger.

Starter code

main.dart
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: SayacEkrani());
  }
}

class SayacEkrani extends StatefulWidget {
  @override
  _SayacEkraniState createState() => _SayacEkraniState();
}

class _SayacEkraniState extends State<SayacEkrani> {
  int _sayac = 0;
  String _durum = 'bekliyor';

  // _artir ve _azalt: setState ile _sayac'ı değiştir
  // _durumYukle: async, mounted kontrolü, setState ile _durum='hazır'

  @override
  void initState() {
    super.initState();
    print('başlangıç: $_sayac');
    _durumYukle();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Sayaç - $_durum')),
      body: Center(child: Gosterici()),
      floatingActionButton: Row(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          FloatingActionButton(
            onPressed: _azalt,
            child: Icon(Icons.remove),
          ),
          SizedBox(width: 8),
          FloatingActionButton(
            onPressed: _artir,
            child: Icon(Icons.add),
          ),
        ],
      ),
    );
  }
}

class Gosterici extends StatelessWidget {
  // deger field ve constructor ekle

  @override
  Widget build(BuildContext context) {
    return Text('$deger', style: TextStyle(fontSize: 48));
  }
}

Sample solution

main.dart
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: SayacEkrani());
  }
}

class SayacEkrani extends StatefulWidget {
  @override
  _SayacEkraniState createState() => _SayacEkraniState();
}

class _SayacEkraniState extends State<SayacEkrani> {
  int _sayac = 0;
  String _durum = 'bekliyor';

  Future<void> _durumYukle() async {
    await Future.delayed(Duration(milliseconds: 100));
    if (mounted) {
      setState(() {
        _durum = 'hazır';
      });
    }
  }

  void _artir() {
    setState(() {
      _sayac++;
    });
  }

  void _azalt() {
    setState(() {
      _sayac--;
    });
  }

  @override
  void initState() {
    super.initState();
    print('başlangıç: $_sayac');
    _durumYukle();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Sayaç - $_durum')),
      body: Center(child: Gosterici(deger: _sayac)),
      floatingActionButton: Row(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          FloatingActionButton(
            onPressed: _azalt,
            child: Icon(Icons.remove),
          ),
          SizedBox(width: 8),
          FloatingActionButton(
            onPressed: _artir,
            child: Icon(Icons.add),
          ),
        ],
      ),
    );
  }
}

class Gosterici extends StatelessWidget {
  final int deger;
  Gosterici({required this.deger});

  @override
  Widget build(BuildContext context) {
    return Text('$deger', style: TextStyle(fontSize: 48));
  }
}

Expected output

başlangıç: 0

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 What should you do to safely call setState after awaiting a Future?

  • Check if (mounted) first Correct answer
  • Call dispose first
  • Call initState again first
  • Cancel the Future first

Explanation: After async the widget may have been disposed; if (mounted) verifies the State is still in the tree before calling setState.

2 Define the child's callback field

Question
class Dugme extends StatelessWidget {
  final VoidCallback ____;
  Dugme({required this.onTikla});
  @override
  Widget build(BuildContext context) => Text('Düğme');
}
Answer
class Dugme extends StatelessWidget {
  final VoidCallback onTikla;
  Dugme({required this.onTikla});
  @override
  Widget build(BuildContext context) => Text('Düğme');
}

Explanation: In the lifting pattern, the child receives the callback as a constructor parameter and stores it in a field; the parent updates state with setState.

3 setState section parts

Term Meaning
setState Notifies the framework of state change
mounted Safety check before setState after async
Lifting state up Moves state to siblings' common parent
Callback Child's way to report events to parent

All lessons in Intermediate