react_hooks 1.0.0
react_hooks: ^1.0.0 copied to clipboard
A Flutter package that provides React-like hooks (useState, useEffect) for state management and side effects in Flutter apps.
import 'package:flutter/material.dart';
import 'package:react_hooks/react_hooks.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'React Hooks Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const HomePage(),
);
}
}
/// Home page - Simple navigation
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('React Hooks Demo'),
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () => Navigator.push(
context,
MaterialPageRoute(builder: (context) => const BasicExample()),
),
child: const Text('Basic useState Example'),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () => Navigator.push(
context,
MaterialPageRoute(builder: (context) => const ContextExample()),
),
child: const Text('useContext Example'),
),
],
),
),
);
}
}
// =============================================================================
// Basic useState Example
// =============================================================================
class BasicExample extends HookWidget {
const BasicExample({super.key});
@override
Widget build(BuildContext context) {
final countState = useState(0);
useEffect(() {
print('Count: ${countState.value}');
return null;
}, [countState.value]);
return Scaffold(
appBar: AppBar(title: const Text('useState Example')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Count: ${countState.value}', style: const TextStyle(fontSize: 24)),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () => countState.setValue(countState.value - 1),
child: const Text('-'),
),
const SizedBox(width: 20),
ElevatedButton(
onPressed: () => countState.setValue(0),
child: const Text('Reset'),
),
const SizedBox(width: 20),
ElevatedButton(
onPressed: () => countState.setValue(countState.value + 1),
child: const Text('+'),
),
],
),
],
),
),
);
}
}
// =============================================================================
// useContext Example
// =============================================================================
/// User data model
class User {
final String name;
final int age;
const User({required this.name, required this.age});
User copyWith({String? name, int? age}) {
return User(
name: name ?? this.name,
age: age ?? this.age,
);
}
}
/// Counter context value
class CounterContextValue {
final int count;
final void Function() increment;
final void Function() decrement;
final void Function() reset;
CounterContextValue({
required this.count,
required this.increment,
required this.decrement,
required this.reset,
});
}
/// User context value
class UserContextValue {
final User user;
final void Function(String) setName;
final void Function(int) setAge;
UserContextValue({
required this.user,
required this.setName,
required this.setAge,
});
}
/// Combined context value
class AppContextValue {
final CounterContextValue counter;
final UserContextValue user;
AppContextValue({
required this.counter,
required this.user,
});
}
/// useCounter custom hook
CounterContextValue useCounter([int initialValue = 0]) {
final countState = useState(initialValue);
void increment() => countState.update((prev) => prev + 1);
void decrement() => countState.update((prev) => prev - 1);
void reset() => countState.setValue(initialValue);
return CounterContextValue(
count: countState.value,
increment: increment,
decrement: decrement,
reset: reset,
);
}
/// useUser custom hook
UserContextValue useUser([User? initialUser]) {
final userState = useState<User>(initialUser ?? const User(name: 'John Doe', age: 25));
void setName(String name) {
userState.setValue(userState.value.copyWith(name: name));
}
void setAge(int age) {
userState.setValue(userState.value.copyWith(age: age));
}
return UserContextValue(
user: userState.value,
setName: setName,
setAge: setAge,
);
}
/// Context example main page
class ContextExample extends HookWidget {
const ContextExample({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('useContext Example')),
body: HookProvider<AppContextValue>(
create: () => AppContextValue(
counter: useCounter(0),
user: useUser(),
),
child: const Column(
children: [
Expanded(child: HeaderComponent()),
Expanded(child: CounterDisplay()),
Expanded(child: UserDisplay()),
Expanded(child: UserControls()),
Expanded(child: CounterControls()),
],
),
),
);
}
}
/// Parent component - Header
class HeaderComponent extends HookWidget {
const HeaderComponent({super.key});
@override
Widget build(BuildContext context) {
return const Center(
child: Text(
'Context Example: Counter + User',
style: TextStyle(fontSize: 20),
),
);
}
}
/// Child component - Display counter
class CounterDisplay extends HookWidget {
const CounterDisplay({super.key});
@override
Widget build(BuildContext context) {
final app = useContext<AppContextValue>(context);
return Center(
child: Text(
'Count: ${app.counter.count}',
style: const TextStyle(fontSize: 24),
),
);
}
}
/// Child component - Display user info
class UserDisplay extends HookWidget {
const UserDisplay({super.key});
@override
Widget build(BuildContext context) {
final app = useContext<AppContextValue>(context);
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'User: ${app.user.user.name}',
style: const TextStyle(fontSize: 20),
),
Text(
'Age: ${app.user.user.age}',
style: const TextStyle(fontSize: 16),
),
],
),
);
}
}
/// Child component - User controls
class UserControls extends HookWidget {
const UserControls({super.key});
@override
Widget build(BuildContext context) {
final app = useContext<AppContextValue>(context);
final nameController = useTextEditingController(app.user.user.name);
return Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Row(
children: [
Expanded(
child: TextField(
controller: nameController.controller,
decoration: const InputDecoration(labelText: 'Name'),
),
),
const SizedBox(width: 10),
ElevatedButton(
onPressed: () => app.user.setName(nameController.value),
child: const Text('Update'),
),
],
),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () => app.user.setAge(app.user.user.age - 1),
child: const Text('Age -'),
),
const SizedBox(width: 20),
ElevatedButton(
onPressed: () => app.user.setAge(app.user.user.age + 1),
child: const Text('Age +'),
),
],
),
],
),
);
}
}
/// Child component - Counter control buttons
class CounterControls extends HookWidget {
const CounterControls({super.key});
@override
Widget build(BuildContext context) {
final app = useContext<AppContextValue>(context);
return Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: app.counter.decrement,
child: const Text('Count -'),
),
const SizedBox(width: 20),
ElevatedButton(
onPressed: app.counter.reset,
child: const Text('Reset'),
),
const SizedBox(width: 20),
ElevatedButton(
onPressed: app.counter.increment,
child: const Text('Count +'),
),
],
),
);
}
}