Question #95EasyFlutter Basics

What is flutter hook ?

#flutter

Answer

Overview

Flutter Hooks is a package that brings React-style hooks to Flutter, allowing you to manage state and side effects in functional widgets with less boilerplate than StatefulWidget.


Installation

Add to

text
pubspec.yaml
:

yaml
dependencies:
  flutter_hooks: ^0.20.0

What Are Hooks?

Hooks are reusable functions that manage widget state, lifecycle, and side effects inside

text
HookWidget
(similar to React hooks).

Traditional StatefulWidget:

dart
class Counter extends StatefulWidget {
  
  _CounterState createState() => _CounterState();
}

class _CounterState extends State<Counter> {
  int count = 0;

  
  Widget build(BuildContext context) {
    return Text('$count');
  }
}

With Flutter Hooks:

dart
import 'package:flutter_hooks/flutter_hooks.dart';

class Counter extends HookWidget {
  
  Widget build(BuildContext context) {
    final count = useState(0); // Hook manages state

    return Text('${count.value}');
  }
}

Core Hooks

1. useState — State Management

Manages local state (like

text
setState
).

dart
class Counter extends HookWidget {
  
  Widget build(BuildContext context) {
    final count = useState(0); // Initial value = 0

    return Column(
      children: [
        Text('Count: ${count.value}'),
        ElevatedButton(
          onPressed: () => count.value++, // Update state
          child: Text('Increment'),
        ),
      ],
    );
  }
}

2. useEffect — Side Effects

Runs side effects (like

text
initState
,
text
dispose
).

dart
class Timer extends HookWidget {
  
  Widget build(BuildContext context) {
    final count = useState(0);

    useEffect(() {
      final timer = Timer.periodic(Duration(seconds: 1), (_) {
        count.value++;
      });

      return timer.cancel; // Cleanup (like dispose)
    }, []); // Empty list = run once on mount

    return Text('Elapsed: ${count.value}s');
  }
}

Dependencies:

dart
// Run effect when `userId` changes
useEffect(() {
  fetchUserData(userId);
  return null; // No cleanup
}, [userId]); // Re-run when userId changes

3. useMemoized — Expensive Calculations

Caches computed values (like

text
useMemo
in React).

dart
class ExpensiveList extends HookWidget {
  
  Widget build(BuildContext context) {
    final items = useMemoized(() {
      return List.generate(1000, (i) => 'Item $i'); // Only computed once
    });

    return ListView(children: items.map((e) => Text(e)).toList());
  }
}

4. useTextEditingController

Creates and disposes

text
TextEditingController
.

dart
class SearchBar extends HookWidget {
  
  Widget build(BuildContext context) {
    final controller = useTextEditingController();

    return TextField(
      controller: controller,
      onChanged: (value) => print(value),
    );
    // Auto-disposed when widget unmounts
  }
}

5. useAnimationController

Creates

text
AnimationController
with auto-disposal.

dart
class AnimatedBox extends HookWidget {
  
  Widget build(BuildContext context) {
    final controller = useAnimationController(
      duration: Duration(seconds: 1),
    );

    return GestureDetector(
      onTap: () => controller.forward(),
      child: FadeTransition(
        opacity: controller,
        child: Container(width: 100, height: 100, color: Colors.blue),
      ),
    );
  }
}

6. useFuture — Async Data

Handles async operations.

dart
class UserProfile extends HookWidget {
  
  Widget build(BuildContext context) {
    final userSnapshot = useFuture(fetchUser());

    if (userSnapshot.connectionState == ConnectionState.waiting) {
      return CircularProgressIndicator();
    }

    if (userSnapshot.hasError) {
      return Text('Error: ${userSnapshot.error}');
    }

    return Text('User: ${userSnapshot.data?.name}');
  }
}

7. useStream — Stream Listening

Subscribes to streams automatically.

dart
class ChatMessages extends HookWidget {
  
  Widget build(BuildContext context) {
    final messagesSnapshot = useStream(messageStream);

    final messages = messagesSnapshot.data ?? [];

    return ListView.builder(
      itemCount: messages.length,
      itemBuilder: (_, i) => Text(messages[i]),
    );
  }
}

Custom Hooks

Create reusable hooks.

dart
// Custom hook for debounced search
ValueNotifier<String> useDebounce(String value, Duration delay) {
  final debounced = useState(value);

  useEffect(() {
    final timer = Timer(delay, () {
      debounced.value = value;
    });

    return timer.cancel;
  }, [value]);

  return debounced;
}

// Usage
class SearchScreen extends HookWidget {
  
  Widget build(BuildContext context) {
    final query = useState('');
    final debouncedQuery = useDebounce(query.value, Duration(milliseconds: 500));

    useEffect(() {
      if (debouncedQuery.value.isNotEmpty) {
        searchAPI(debouncedQuery.value);
      }
      return null;
    }, [debouncedQuery.value]);

    return TextField(onChanged: (val) => query.value = val);
  }
}

Comparison: StatefulWidget vs HookWidget

FeatureStatefulWidgetHookWidget
BoilerplateHigh (2 classes)Low (1 class)
State management
text
setState()
text
useState()
Lifecycle
text
initState
,
text
dispose
text
useEffect()
ControllersManual creation/disposalAuto-managed
Code reuseMixins (limited)Custom hooks ✅
PerformanceSameSame

Best Practices

dart
// ✅ Use hooks at top level (not inside conditionals)
class MyWidget extends HookWidget {
  
  Widget build(BuildContext context) {
    final count = useState(0); // ✅ Top level

    if (count.value > 5) {
      // final other = useState(0); // ❌ Conditional hook (error)
    }

    return Text('$count');
  }
}

// ✅ Prefer HookWidget for simple state
// ❌ Don't use for complex state (use BLoC, Riverpod instead)

// ✅ Cleanup in useEffect
useEffect(() {
  final subscription = stream.listen(...);
  return subscription.cancel; // ✅ Cleanup
}, []);

When to Use Flutter Hooks

  • Simple local state (counters, toggles, form inputs)
  • Animations (auto-managed controllers)
  • Side effects (API calls, timers, subscriptions)
  • Reusable logic (custom hooks)
  • Complex state (use BLoC, Riverpod, Provider instead)
  • Large apps (hooks are for widget-level state)

Common Hooks Summary

HookPurposeExample
text
useState
Local stateCounter, toggle
text
useEffect
Side effectsAPI calls, timers
text
useMemoized
Cache valuesExpensive calculations
text
useFuture
Async dataAPI responses
text
useStream
Stream dataReal-time updates
text
useTextEditingController
Text inputSearch, forms
text
useAnimationController
AnimationsFades, slides

Learn more: Flutter Hooks Package