In initState function in StatefulWidget in Flutter, should super.initState() be called before any function or after any function?
#initstate#lifecycle#statefulwidget#best-practices
Answer
Quick Answer
must be called FIRST — before any other code in textsuper.initState()
text
initState()dartvoid initState() { super.initState(); // ✅ FIRST - Always call this first // Then your initialization code _controller = AnimationController(vsync: this); _fetchData(); }
Why Call super.initState() First?
Reason 1: Framework Initialization
The
text
super.initState()- Initializes the widget's internal state
- Sets up the widget's relationship with the widget tree
- Prepares the for usetext
BuildContext - Registers the widget with the framework
If you don't call it first:
dartvoid initState() { _fetchData(); // ❌ Might fail - widget not fully initialized super.initState(); // ❌ Too late! }
Reason 2: BuildContext Availability
dartvoid initState() { super.initState(); // ✅ First - initializes context // Now context is safe to use final theme = Theme.of(context); // ✅ Works final mediaQuery = MediaQuery.of(context); // ✅ Works }
Wrong order:
dartvoid initState() { final theme = Theme.of(context); // ❌ Context not ready super.initState(); // ❌ Too late }
Official Documentation
From Flutter's StatefulWidget documentation:
"If you override this method, make sure to call
as the first line."textsuper.initState()
This is a hard requirement, not a suggestion.
Correct Pattern
✅ Correct Example
dartclass MyWidget extends StatefulWidget { _MyWidgetState createState() => _MyWidgetState(); } class _MyWidgetState extends State<MyWidget> { late AnimationController _controller; late Future<List<User>> _usersFuture; Timer? _timer; void initState() { super.initState(); // ✅ FIRST LINE // Initialize controllers _controller = AnimationController( vsync: this, duration: Duration(seconds: 2), ); // Fetch data _usersFuture = _fetchUsers(); // Start timer _timer = Timer.periodic(Duration(seconds: 1), (timer) { print('Tick ${timer.tick}'); }); // Add listeners _controller.addListener(() { print('Animation: ${_controller.value}'); }); } Future<List<User>> _fetchUsers() async { // API call return []; } void dispose() { _controller.dispose(); _timer?.cancel(); super.dispose(); // Dispose is opposite - call last } Widget build(BuildContext context) { return Container(); } }
❌ Wrong Example
dartvoid initState() { // ❌ WRONG - initialization before super.initState() _controller = AnimationController(vsync: this); _fetchData(); super.initState(); // ❌ Too late! }
Why it's wrong:
- Widget not fully initialized yet
- might not be readytext
BuildContext - Framework state not set up
- Can cause runtime errors or crashes
Common Use Cases
1. Initializing Controllers
dartvoid initState() { super.initState(); // ✅ First // Initialize animation controller _animationController = AnimationController( vsync: this, duration: Duration(milliseconds: 500), ); // Initialize text controller _textController = TextEditingController(text: 'Initial value'); // Initialize scroll controller _scrollController = ScrollController(); }
2. Fetching Data
dartvoid initState() { super.initState(); // ✅ First // Fetch data when widget loads _fetchUserData(); } Future<void> _fetchUserData() async { final response = await http.get(Uri.parse('https://api.example.com/user')); setState(() { _userData = jsonDecode(response.body); }); }
3. Setting Up Listeners
dartvoid initState() { super.initState(); // ✅ First // Add listener to animation controller _controller.addListener(() { setState(() { _progress = _controller.value; }); }); // Add listener to text field _textController.addListener(() { print('Text changed: ${_textController.text}'); }); }
4. Starting Timers
dartvoid initState() { super.initState(); // ✅ First // Start periodic timer _timer = Timer.periodic(Duration(seconds: 5), (timer) { _refreshData(); }); // One-time delayed action Future.delayed(Duration(seconds: 2), () { setState(() { _showWelcome = true; }); }); }
5. Accessing Widget Properties
dartclass UserProfile extends StatefulWidget { final String userId; final bool autoRefresh; UserProfile({required this.userId, this.autoRefresh = false}); _UserProfileState createState() => _UserProfileState(); } class _UserProfileState extends State<UserProfile> { void initState() { super.initState(); // ✅ First // Access widget properties via widget.propertyName print('User ID: ${widget.userId}'); // Fetch user data _fetchUser(widget.userId); // Conditional initialization if (widget.autoRefresh) { _startAutoRefresh(); } } void _fetchUser(String userId) { // Fetch user data } void _startAutoRefresh() { Timer.periodic(Duration(seconds: 30), (timer) { _fetchUser(widget.userId); }); } Widget build(BuildContext context) { return Container(); } }
What Happens If You Don't Call super.initState()?
Analyzer Warning
dartvoid initState() { // Missing super.initState() _controller = AnimationController(vsync: this); } // ⚠️ Analyzer warning: // "Missing call to 'super.initState()'"
Runtime Issues
Potential problems:
- Widget not properly initialized
- BuildContext not fully set up
- Framework state inconsistencies
- Unexpected crashes or errors
- Memory leaks
initState vs dispose Order
Key difference:
| Method | super Call Placement | Reason |
|---|---|---|
text | FIRST (before your code) | Framework must initialize first |
text | LAST (after your code) | Clean up your resources before framework cleanup |
Correct Pattern
dartclass _MyWidgetState extends State<MyWidget> { late AnimationController _controller; late Timer _timer; void initState() { super.initState(); // ✅ FIRST - Framework initializes _controller = AnimationController(vsync: this); _timer = Timer.periodic(Duration(seconds: 1), (_) {}); } void dispose() { // ✅ Clean up your resources first _controller.dispose(); _timer.cancel(); super.dispose(); // ✅ LAST - Framework cleans up } Widget build(BuildContext context) { return Container(); } }
Best Practices
✅ DO
dartvoid initState() { super.initState(); // ✅ First line always // Initialize in logical order _initializeControllers(); _fetchData(); _setupListeners(); }
❌ DON'T
dartvoid initState() { _setupEverything(); // ❌ Don't call functions before super super.initState(); // ❌ Too late }
dartvoid initState() { // ❌ Don't forget super.initState() entirely _controller = AnimationController(vsync: this); }
dartvoid initState() { super.initState(); setState(() {}); // ❌ Don't call setState in initState // Use addPostFrameCallback instead }
When You Need to Call setState in initState
Problem: Can't call
text
setState()text
initState()Solution: Use
text
addPostFrameCallbackdartvoid initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { // This runs after the first frame is rendered setState(() { _isReady = true; }); }); }
Summary
Rule: Always call
as the first line in yourtextsuper.initState()method.textinitState()
Why: The framework needs to initialize the widget before you can safely use it.
Opposite: In
, calltextdispose()as the last line (after cleaning up your resources).textsuper.dispose()
Required: Not optional — Flutter will show an analyzer warning if you forget.