skip to Main Content

What is the best practice in flutter, should each Widget have a controller attached to it or the Widget can have also presentation logic inside?

As an example shown here is some chatGPT generated code for a login widget (so please ignore if some parts are incorrect). If the user is logged in it will show logout button or login button when is logged out.

// Create a Riverpod provider for the authentication state
final authProvider = ChangeNotifierProvider<AuthController, bool>((ref) {
  return AuthController();
});

class AuthController extends ChangeNotifier {
}

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Authentication Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              'Welcome to the App!',
            ),
            SizedBox(height: 20),
            Consumer(
              builder: (context, watch, child) {
                final isAuthenticated = watch(authProvider);

                return Column(
                  children: [
                    if (!isAuthenticated) <----- here
                      ElevatedButton(
                        onPressed: () {
                          context.read(authProvider.notifier).login();
                        },
                        child: Text('Login'),
                      ),
                    if (isAuthenticated) <----- here
                      ElevatedButton(
                        onPressed: () {
                          context.read(authProvider.notifier).logout();
                        },
                        child: Text('Logout'),
                      ),
                  ],

In this case the Widget will react to a Riverpod provider and when update it’s UI. I’ve marked where the Widget decides what to show base on the info from the provider.

Does it make sense to have an extra controller object that communicates with the provider and updates the UI in this case?

Thanks

2

Answers


  1. Generally, the best practice is to either keep all the controllers in a folder named controller or inside a method folder wherein it contains method_screen.dart, method_model.dart & method_controller.dart. These are very efficient practices for debugging and for quick and easy update purpose.

    Also in this case it acts as an object to get called from the function. So yes it’s necessary to have the controller.

    Login or Signup to reply.
  2. The use case for Notifier is exactly what you are indicating, to have an object (service, controller, …) which handles and notifies for changes in a data model which is provided by a provider.

    You can even have a getter ("view" in the example) to expose the current state from the notifier (controller). Beware that state exposed by the notifier it will not notify the listeners when the state changes. You shall use the actual provider for that purpose.

    // Provider for ViewModel
    final viewModelProvider = NotifierProvider<ViewModelController, ViewModel>(() {
      return ViewModelController();
    });
    
    @immutable
    class ViewModel {
      final String homeTitle;
    
      const ViewModel(this.homeTitle);
    
      ViewModel copyWith({final String? homeTitle}) {
        return ViewModel(homeTitle ?? this.homeTitle);
      }
    }
    
    class ViewModelController extends Notifier<ViewModel> {
      @override
      ViewModel build() {
        return const ViewModel("Home");
      }
    
      void updateHomeTitle(final String title) {
        // Change the title of home and notify listeners.
        state = state.copyWith(homeTitle: title);
      }
    
      /// Getter to expose the current state of the ViewModel.
      ViewModel get view => state;
    }
    

    Then in your code, wherever you need to have a controller you would:

    final ViewModelController controller = ref.watch(viewModelProvider.notifier);
    

    That "controller" can be passed as argument to functions or widgets as any other object.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search