YouTip LogoYouTip

Flutter Stateless Stateful

Understanding the difference between StatelessWidget and StatefulWidget is fundamental to Flutter development. This section will deeply analyze the usage scenarios and internal mechanisms of these two types of Widgets. * * * ## Core Differences There are two main types of Widgets in Flutter, and their fundamental difference lies in whether they can hold mutable state. | Feature | StatelessWidget | StatefulWidget | | --- | --- | --- | | State | Immutable | Mutable | | Rebuild Timing | Only when parent Widget rebuilds | When state changes + parent Widget rebuilds | | Performance | Higher (no need to listen for state) | Slightly lower (requires state management) | | Use Cases | Static content | Dynamic interactive content | * * * ## StatelessWidget Explained StatelessWidget is suitable for content that does not change over time. Once created, all its properties are final and cannot be modified. ### Use Cases * Displaying static text, images, icons * Showing data lists (data source from parent Widget) * Layout containers without user interaction * Read-only display parts in forms ## Example: Complete StatelessWidget Example import'package:flutter/material.dart'; // User information display component (stateless) class UserCard extends StatelessWidget { // Properties defined as final to ensure immutability final String name; final String email; final String avatarUrl; // const constructor improves performance const UserCard({ super.key, required this.name, required this.email, this.avatarUrl='', }); @override Widget build(BuildContext context){ return Card( child: Padding( padding:const EdgeInsets.all(16.0), child: Row( children:[ // Avatar CircleAvatar( backgroundImage: avatarUrl.isNotEmpty ? NetworkImage(avatarUrl) :null, child: avatarUrl.isEmpty ?const Icon(Icons.person) :null, ), const SizedBox(width:16), // User info Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children:[ Text( name, style:const TextStyle( fontSize:18, fontWeight: FontWeight.bold, ), ), const SizedBox(height:4), Text( email, style: TextStyle( color: Colors.grey, ), ), ], ), ), ], ), ), ); } } * * * ## StatefulWidget Explained StatefulWidget is suitable for scenarios that require responding to user interactions or data changes. It consists of two parts: the Widget itself (immutable) and a State object (mutable). ### Use Cases * Dynamic data such as counters, timers * Form inputs * Animation control * Network request status display * User interaction responses ### State Object Lifecycle | Method | Description | | --- | --- | | initState | Called when Widget is first created, used for initializing state | | didChangeDependencies | Called when Widget's dependencies change | | build | Builds UI, called every time state changes | | didUpdateWidget | Called when parent Widget rebuilds | | dispose | Called when Widget is removed, used for resource cleanup | ## Example: Complete StatefulWidget Example import'package:flutter/material.dart'; // Counter application class CounterApp extends StatefulWidget { const CounterApp({super.key}); @override State createState()=> _CounterAppState(); } class _CounterAppState extends State{ // Counter state int _counter =0; // Timer (for demo purposes) Timer? _timer; // 1. initState - Initialize state @override void initState(){ super.initState(); // Initialize counter _counter =0; // Start a timer (increase every second) _timer = Timer.periodic(const Duration(seconds:1),(timer){ _increment(); }); } // 2. didChangeDependencies - Called when dependencies change @override void didChangeDependencies(){ super.didChangeDependencies(); } // 3. build - Build UI @override Widget build(BuildContext context){ return Scaffold( appBar: AppBar( title:const Text('Counter'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children:[ const Text( 'Current count:', style: TextStyle(fontSize:20), ), Text( '$_counter', style:const TextStyle( fontSize:48, fontWeight: FontWeight.bold, ), ), ], ), ), // Increment button floatingActionButton: FloatingActionButton( onPressed: _increment, child:const Icon(Icons.add), ), ); } // Method to increment counter void _increment(){ // Must call setState to trigger UI update setState((){ _counter++; }); } // 4. didUpdateWidget - Called when parent Widget rebuilds @override void didUpdateWidget(CounterApp oldWidget){ super.didUpdateWidget(oldWidget); } // 5. dispose - Clean up resources @override void dispose(){ // Cancel timer to prevent memory leaks _timer?.cancel(); super.dispose(); } } * * * ## Proper Usage of setState In StatefulWidget, you must use setState to notify Flutter that the state has changed. ### Correct Usage ## Example: Correct setState Usage // Correct: Update state within setState void _increment(){ setState((){ _counter++; }); } // Correct: State updates not related to UI don't require setState void _someInternalLogic(){ // Internal logic, doesn't affect UI _calculateSomething(); } // Correct: Update state after asynchronous operations Future _loadData() async { final data = await fetchData(); setState((){ _items = data; }); } ### Incorrect Usage ## Example: Incorrect setState Usage // Incorrect: Modify state but don't call setState void _increment(){ _counter++;// State changed, but UI won't update! } // Incorrect: Call setState inside build method @override Widget build(BuildContext context){ // Never call setState inside build! setState((){ _counter++;// This causes infinite loop }); return Text('$_counter'); } > setState triggers a rebuild of the build method on the next frame draw. > > > Frequent calls to setState or calling setState inside the build method can cause performance issues. * * * ## How to Choose When developing, choose the appropriate Widget type based on actual needs: ### Choose StatelessWidget When * The appearance of the Widget does not depend on any mutable state * All needed data is passed through constructor from parent Widget * The Widget does not need to respond to user interaction * You want optimal performance ### Choose StatefulWidget When * The Widget needs to maintain internal state * Need to respond to user input (taps, scrolls, etc.) * Need to respond to data changes (e.g., network request returns) * Need to control animations
← Flutter ContainerFlutter Project Structure β†’