import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) => const MaterialApp( debugShowCheckedModeBanner: false, home: MyHomePage(), ); } class MyHomePage extends StatefulWidget { const MyHomePage({super.key}); @override State createState() => _MyHomePageState(); } class _MyHomePageState extends State { final ValueNotifier name = ValueNotifier('Jane'); final ValueNotifier surname = ValueNotifier('Doe'); late final ValueNotifier fullName; @override void initState() { super.initState(); fullName = ValueNotifier('${name.value} ${surname.value}'); name.addListener(_updateFullName); surname.addListener(_updateFullName); } /// This ensures that changing first or surname triggers /// a rebuild void _updateFullName() { fullName.value = '${name.value} ${surname.value}'; } @override Widget build(BuildContext context) => Scaffold( appBar: AppBar( title: const Text('ValueNotifier Example'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ ValueListenableBuilder( valueListenable: fullName, builder: (context, value, child) => Text( '${name.value} ${surname.value}', style: Theme.of(context).textTheme.headlineMedium, ), ), ElevatedButton( onPressed: () => name.value = name.value == 'Jane' ? 'John' : 'Jane', child: const Text('Change First Name'), ), ElevatedButton( onPressed: () => surname.value = surname.value == 'Doe' ? 'Dop' : 'Doe', child: const Text('Change Surname'), ), ], ), ), ); @override void dispose() { name.dispose(); surname.dispose(); super.dispose(); } }