Flutter essentials: 50 cards on Dart, widgets, state and layout
Flutter and Dart basics: null safety, futures and streams, stateless vs stateful widgets, setState, hot reload, keys, layout and state management.
Practice now
Study without an account
String vs String? in DartScheduled with the default Askesis timings. Progress is saved in this browser.
All 50 cards
- 1
StringvsString?in DartWith sound null safety (required since Dart 3), aStringcan never benull; aString?can, and the compiler makes you handle that case before using it - 2Dart’s null-aware operatorsdart
final name = user?.name ?? 'Guest'; cache ??= {}; final len = maybeText!.length; // throws if null?.short-circuits to null,??supplies a default,??=assigns only if null, and!asserts non-null. - 3What does
latedo?Declares a non-nullable variable that is initialized after its declaration; reading it before it is assigned throws aLateInitializationErrorlate final config = loadConfig();also makes the initializer lazy: it runs on first access. - 4
finalvsconstfinalis set once, at runtime;constis a compile-time constant that is deeply immutable and canonicalized, so identicalconstvalues are the same instancedartfinal now = DateTime.now(); // fine const appName = 'Askesis'; // fine const later = DateTime.now(); // compile error - 5
varvsdynamicvsObject?varinfers a fixed static type from the initializer;dynamicturns off static checking;Object?accepts anything but still requires a check or cast before you use it - 6What happens here?dart
var x = 'hi'; x = 5;A compile error:varinferredxas aString, so it can’t be assigned anint - 7String interpolation in Dartdart
print('Hello, $name! You have ${items.length} items.');Use${…}for anything beyond a simple identifier. - 8Build a list with collection
if,forand spreaddartfinal menu = [ ...baseItems, if (isAdmin) 'Admin panel', for (final id in recentIds) 'Item $id', ]; - 9What does the cascade operator
..do?Performs several operations on the same object and evaluates to that objectdartfinal paint = Paint() ..color = Colors.blue ..strokeWidth = 2; - 10Named and required parametersdart
void greet({required String name, String greeting = 'Hi'}) { print('$greeting, $name'); } greet(name: 'Ada');Named parameters go in{}; optional positional parameters go in[]. - 11A class with a const constructor and initializing formalsdart
class Point { const Point(this.x, this.y); final int x; final int y; }this.xassigns the field straight from the parameter. Aconstconstructor requires all fields to befinal. - 12Return two values from a functiondart
(String, int) nameAndAge() => ('Ada', 36); final (name, age) = nameAndAge();Records and destructuring patterns arrived in Dart 3. - 13Switch exhaustively over a sealed classdart
sealed class Shape {} class Square extends Shape { Square(this.side); final double side; } class Circle extends Shape { Circle(this.radius); final double radius; } double area(Shape s) => switch (s) { Square(side: var l) => l * l, Circle(radius: var r) => 3.14159 * r * r, };Sealed classes and switch expressions (Dart 3) let the compiler check that every subtype is handled. - 14What is a
Future?A value (or error) that will be available later. Mark a functionasyncandawaitfutures inside it as if they were synchronousdartFuture<User> loadUser(int id) async { final res = await http.get(Uri.parse('$baseUrl/users/$id')); return User.fromJson(jsonDecode(res.body)); } - 15What does this print?dart
void main() { print('A'); Future(() => print('B')); print('C'); }A,C,B: the future’s callback is queued on the event loop and runs only after the current synchronous code finishes - 16Wait for several futures in paralleldart
final results = await Future.wait([fetchUser(), fetchPosts()]);With records (Dart 3):final (user, posts) = await (fetchUser(), fetchPosts()).wait; - 17
FuturevsStreamAFuturedelivers one value or error; aStreamdelivers a sequence of them over time, consumed withawait fororlistenA single-subscription stream can be listened to only once; a broadcast stream allows many listeners. - 18Write a function that produces a streamdart
Stream<int> countdown(int from) async* { for (var i = from; i > 0; i--) { yield i; await Future.delayed(const Duration(seconds: 1)); } } - 19How do you keep heavy CPU work from freezing a Flutter UI?Isolates don’t share memory.Dart runs your code on a single thread per isolate, so a long computation blocks frames. Move it to another isolatedart
final data = await Isolate.run(() => parseHugeJson(text)); - 20What is a widget?An immutable description of part of the UI. Flutter builds a tree of widgets and uses it to create and update the longer-lived elements and render objects that actually lay out and paint
- 21
StatelessWidgetvsStatefulWidgetA stateless widget depends only on its constructor arguments and inherited data; a stateful widget has a separateStateobject that persists across rebuilds and can change over time - 22A minimal
StatelessWidgetdartclass Greeting extends StatelessWidget { const Greeting({super.key, required this.name}); final String name; @override Widget build(BuildContext context) => Text('Hello, $name'); } - 23A counter with
StatefulWidgetdartclass Counter extends StatefulWidget { const Counter({super.key}); @override State<Counter> createState() => _CounterState(); } class _CounterState extends State<Counter> { int _count = 0; @override Widget build(BuildContext context) => ElevatedButton( onPressed: () => setState(() => _count++), child: Text('Tapped $_count times'), ); } - 24What does
setStatedo?Runs your callback, marks theStateas dirty and schedulesbuildto run again. Changing a field withoutsetStateupdates the value but not the screen - 25What should and shouldn’t happen in
build?buildmay run very often, even every frame during an animation, so keep it fast and free of side effects: no network calls, subscriptions or heavy work - 26Key
Statelifecycle methodsinitStateruns once when the state is created (set up controllers and subscriptions);didUpdateWidgetruns when the parent rebuilds with a new widget;disposeruns when it is removed for good (release them)Callsuper.initState()first andsuper.dispose()last. - 27Why add
constto widget constructors and instances?Aconstwidget is created once at compile time and reused, so when its parent rebuilds, Flutter can skip rebuilding that subtreedartconst Padding(padding: EdgeInsets.all(8), child: Text('Hi')) - 28What is a
BuildContext?A handle to a widget’s location in the tree, used to look up ancestors and inherited data:Theme.of(context),MediaQuery.sizeOf(context),Navigator.of(context) - 29What should you check before using
contextafter anawait?That the widget is still in the tree:if (!context.mounted) return;Inside aState, check itsmountedproperty. Using a stale context can throw or act on the wrong screen. - 30Hot reload vs hot restartHot reload injects changed code into the running app and rebuilds the widget tree, keeping state; hot restart reruns the app from
main(), resetting state. Native code changes need a full rebuild - 31Which changes doesn’t hot reload pick up?Code that already ran: edits to
main()orinitState(), and initializers of global variables and static fields. Some type changes, like turning an enum into a class, also need a hot restart - 32What are keys for?They tell Flutter which widget is which when siblings are reordered, inserted or removed, so each
Statestays with the right itemdartTodoTile(key: ValueKey(todo.id), todo: todo) - 33What goes wrong if you reorder stateful list items without keys?Flutter matches widgets by type and position, so each
State(a checkbox’s value, a text field’s contents) stays at its old position and ends up attached to a different item - 34When do you need a
GlobalKey?To reach a widget’sStatefrom elsewhere, such asGlobalKey<FormState>to callvalidate()on aForm, or to keep state while moving a widget to a new parent. They are costly, so use them sparingly - 35Flutter’s core layout rule“Constraints go down. Sizes go up. Parent sets position.” A parent tells each child its minimum and maximum size, the child picks a size within them, and the parent positions it
- 36
RowandColumnalignmentmainAxisAlignmentpositions children along the main axis (horizontal in aRow, vertical in aColumn);crossAxisAlignmentaligns them on the other axis - 37Make a child fill the remaining space in a
RowdartRow( children: [ const Icon(Icons.person), Expanded(child: Text(longName)), ], )Flexiblelets the child be smaller than the space it gets;flex:shares space by ratio. - 38What does a yellow-and-black striped bar on screen mean?An overflow: a child is bigger than the space its parent allows, e.g. long text in a
Row. Fix it withExpandedorFlexible, by wrapping or truncating the text, or by making the area scrollable - 39
SizedBoxvsPaddingvsContainerSizedBoxgives a fixed size or a gap;Paddingadds space around a child;Containercombines padding, margin, size, color and decoration in one widget - 40Overlay one widget on anotherdart
Stack( children: [ Image.asset('photo.jpg'), const Positioned(top: 8, right: 8, child: Icon(Icons.star)), ], ) - 41Show a long list efficientlydart
ListView.builder( itemCount: items.length, itemBuilder: (context, i) => ListTile(title: Text(items[i])), )The builder creates only the items that are on screen, instead of all of them up front. - 42Why does a
ListViewinside aColumnthrow an error?TheColumngives it unbounded height, but aListViewtries to fill all available space. Wrap it inExpandedso it gets the remaining spaceThe error mentions “Vertical viewport was given unbounded height”. - 43Adapt a layout to the space availabledart
LayoutBuilder( builder: (context, constraints) => constraints.maxWidth > 600 ? const WideLayout() : const NarrowLayout(), )MediaQuery.sizeOf(context)gives the whole screen size instead of the parent’s constraints. - 44What does a Flutter app’s entry point look like?dart
void main() => runApp(const MyApp());MyAppusually returns aMaterialApp(theme, routes, localization), and each screen is aScaffoldwith anappBarand abody. - 45Open a new screen and get a result backdart
final color = await Navigator.push<String>( context, MaterialPageRoute(builder: (_) => const PickerPage()), ); // inside PickerPage: Navigator.pop(context, 'blue');Packages like go_router add URL-based, declarative routing on top. - 46How should state be shared between widgets?Keep it local with
setStatewhen one widget needs it; lift it up to a common ancestor when several do; for app-wide state useInheritedWidgetor a package built on the same idea, like provider, Riverpod or Bloc - 47Rebuild part of the UI when a model changes, without packagesdart
class Cart extends ChangeNotifier { final items = <String>[]; void add(String item) { items.add(item); notifyListeners(); } } ListenableBuilder( listenable: cart, builder: (context, _) => Text('${cart.items.length} items'), ) - 48The
FutureBuildergotchaCreating the future insidebuild(future: fetchData()) starts a new request on every rebuild. Create it once, e.g. ininitState, store it in a field, and pass that - 49Add a package to a Flutter projectbash
flutter pub add httpThis adds it underdependenciesinpubspec.yamland fetches it;flutter pub getinstalls everything listed there. - 50Create, check and run a Flutter projectbash
flutter create my_app flutter doctor flutter runflutter doctorreports missing SDKs, devices or tooling setup.
Frequently asked questions
Do I need to know Dart before Flutter?
No. The first part of the deck covers the Dart that Flutter code uses daily: null safety, async/await, streams, collection literals, records and sealed classes.
Which Flutter and Dart versions does it use?
Current Flutter 3 with Dart 3. Dart 3 features such as records, patterns and sealed classes are marked.
Which state management approach should I learn first?
Start with setState, lifting state up and ChangeNotifier, which this deck covers. Packages such as provider, Riverpod and Bloc build on the same ideas.
More in Programming
JavaScript
Master the JavaScript every developer uses daily: scope, closures, equality, array methods, promises, async/await and the event loop.
50 cardsAdvanced JS
Fifty advanced JavaScript cards: event-loop ordering puzzles, generators and async iteration, this binding, Proxy and Reflect, modules, AbortController and coercion edge cases.
50 cardsTypeScript
Learn the TypeScript you use every day: narrowing, generics, keyof, mapped and conditional types, utility types, satisfies and strict mode, with code on every card.
50 cardsPython
Learn idiomatic Python fast: comprehensions, f-strings, args and kwargs, generators, decorators, context managers and the standard library.
50 cardsGit & terminal
The Git commands and shell skills developers use every day: branching, rebasing, undoing mistakes, pipes, redirects, permissions and processes.
50 cardsJava
Core Java with short snippets: equals vs ==, records, sealed types, collections, generics, exceptions, streams, lambdas and JVM basics.
50 cardsC#
C# and .NET fundamentals with short snippets: value vs reference types, properties, records, nullable reference types, LINQ, async/await and DI.
50 cardsKotlin
Kotlin fundamentals with short snippets: null safety, val vs var, data and sealed classes, extension functions, scope functions and coroutines.
50 cardsSwift
Swift fundamentals with short snippets: optionals, structs vs classes, protocols, enums with associated values, closures, ARC, async/await and SwiftUI.
50 cardsPHP
Modern PHP 8 with short snippets: strict types, arrays, match, nullsafe and named arguments, enums, readonly, Composer, PDO and password_hash.
50 cardsRuby
Ruby fundamentals with short snippets: blocks, procs and lambdas, symbols, Enumerable, mixins, truthiness, method_missing, gems and Bundler.
50 cardsGo
Go (Golang) fundamentals with short, idiomatic snippets: slices vs arrays, maps, defer, error wrapping, interfaces, goroutines, channels, select and context.
50 cardsRust
Learn the Rust that the compiler keeps asking about: ownership, borrowing, lifetimes, Option and Result, traits, closures, smart pointers and async.
50 cardsC++
Modern C++ in short snippets: references vs pointers, RAII, smart pointers, move semantics, STL containers and algorithms, const, templates and UB.
50 cardsHaskell
Haskell fundamentals with short code: types and type classes, pattern matching, laziness, Maybe and Either, folds, Functor, Applicative and Monad.
50 cardsElixir
Elixir fundamentals with short snippets: immutability, pattern matching, the pipe operator, Enum vs Stream, processes, GenServer, supervisors and mix.
50 cardsx86-64 assembly
x86-64 assembly in Intel syntax: registers and sub-registers, flags, mov and lea, jumps, the stack frame, the System V calling convention and Linux syscalls.
50 cardsRegex
Learn regular expressions for good: anchors, classes, greedy vs lazy quantifiers, groups, lookarounds, flags, replacements and the backtracking trap.
50 cards