<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Victor Mutethia</title>
    <description>The latest articles on DEV Community by Victor Mutethia (@dev-vickie).</description>
    <link>https://dev.to/dev-vickie</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1072763%2F9737513d-e45a-495e-8fc1-b591033667de.jpeg</url>
      <title>DEV Community: Victor Mutethia</title>
      <link>https://dev.to/dev-vickie</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dev-vickie"/>
    <language>en</language>
    <item>
      <title>Fetching API's with Cubits in Flutter</title>
      <dc:creator>Victor Mutethia</dc:creator>
      <pubDate>Sun, 24 Sep 2023 17:18:11 +0000</pubDate>
      <link>https://dev.to/dev-vickie/fetching-apis-with-cubits-in-flutter-b8f</link>
      <guid>https://dev.to/dev-vickie/fetching-apis-with-cubits-in-flutter-b8f</guid>
      <description>&lt;h2&gt;
  
  
  What are cubits
&lt;/h2&gt;

&lt;p&gt;A Cubit is a simple and efficient way to handle state management in Flutter apps.It's a part of the broader Bloc (Business Logic Component) library, which helps you manage your app's state in a structured and organized manner.&lt;/p&gt;

&lt;h3&gt;
  
  
  Here's a breakdown of what a Cubit is:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;State Management&lt;/strong&gt;: A Cubit helps you manage the different states your app can be in. This is useful for handling data loading, user interactions, and more.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simplicity&lt;/strong&gt;: Cubits are designed to be simple and easy to understand. They are a great choice for small to medium-sized applications or when you want to avoid the complexity of full-blown Blocs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Events and States&lt;/strong&gt;: In a Cubit, you define a series of events that can trigger state changes. For example, you might have an event to fetch data from an API, and the Cubit can have states like "loading," "success," or "error" to represent the various stages of the data-fetching process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UI Integration&lt;/strong&gt;: Cubits update the user interface based on changes in state. This ensures that your app's UI always reflects the current state of your Cubit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Setup
&lt;/h2&gt;

&lt;p&gt;We're going to hit the &lt;a href="https://jsonplaceholder.typicode.com/users" rel="noopener noreferrer"&gt;json placeholder API&lt;/a&gt; and display the list of users in our app.We'll use the &lt;a href="https://pub.dev/packages/dio" rel="noopener noreferrer"&gt;dio&lt;/a&gt; package for handling the network request.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.Add Dependencies
&lt;/h3&gt;

&lt;p&gt;In your &lt;code&gt;pubspec.yaml&lt;/code&gt; file, include these packages under the  dependencies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bloc&lt;/code&gt;  and &lt;code&gt;flutter_bloc&lt;/code&gt; packages for state management &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dio&lt;/code&gt; package for making HTTP requests&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;freezed_annotation&lt;/code&gt; for auto-generating Cubit states&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;json_annotation&lt;/code&gt; for generation of json de/serialization methods&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

dependencies:
  flutter:
    sdk: flutter
  bloc: ^8.1.2
  flutter_bloc: ^8.1.3
  dio: ^5.3.3
  freezed_annotation: ^2.4.1
  json_annotation: ^4.8.1


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  2.Add the dev dependencies
&lt;/h3&gt;

&lt;p&gt;Also add these packages under the dev_dependencies.They help with code generation for the cubits and also with json serialization.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

dev_dependencies:
  freezed: ^2.4.2
  json_serializable: ^6.7.1
  build_runner: ^2.4.6


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  3.Project Structure
&lt;/h3&gt;

&lt;p&gt;This is how we will structure our files for easy maintainability.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

your_project_name/
  lib/
    cubits/
      users_cubit.dart 
      users_states.dart
    models/
      user.dart         
    screens/
      users_page.dart
    main.dart


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Creating the user model
&lt;/h2&gt;

&lt;p&gt;In the &lt;code&gt;lib/models/user.dart&lt;/code&gt; file,create a freezed &lt;code&gt;User&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;@freezed&lt;/strong&gt; annotation is used to generate the boilerplate code for the &lt;code&gt;User&lt;/code&gt; class. This includes the constructor, &lt;code&gt;copyWith&lt;/code&gt; method, &lt;code&gt;toString&lt;/code&gt; method, and operator== method.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

part 'user.freezed.dart';
part 'user.g.dart';

@freezed
class User with _$User {
  const factory User({
    required int id,
    required String name,
    required String username,
    required String email,
    required String phone,
    required String website,
  }) = _User;

  factory User.fromJson(Map&amp;lt;String,dynamic&amp;gt; json) =&amp;gt; _$UserFromJson(json);
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The User class also includes a &lt;code&gt;fromJson&lt;/code&gt; factory method that is used to create a new instance of the &lt;code&gt;User&lt;/code&gt; class from a JSON object. This method is generated using the &lt;code&gt;json_serializable&lt;/code&gt; package, which is a companion package to &lt;code&gt;freezed_annotation&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After doing that you can run this command in your terminal to generate the code:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

dart run build_runner build --delete-conflicting-outputs


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Creating UserStates
&lt;/h2&gt;

&lt;p&gt;In the &lt;code&gt;lib/cubits/users_states.dart&lt;/code&gt; we create a &lt;code&gt;UserStates&lt;/code&gt; class.&lt;br&gt;
The &lt;code&gt;UserStates&lt;/code&gt; class is used to represent the different states that the &lt;code&gt;User&lt;/code&gt; list can have in our application,that is, &lt;code&gt;initial&lt;/code&gt; state,&lt;code&gt;loading&lt;/code&gt; state,&lt;code&gt;error&lt;/code&gt; state and &lt;code&gt;success&lt;/code&gt; state.&lt;/p&gt;

&lt;p&gt;The class is also marked with the &lt;strong&gt;@freezed&lt;/strong&gt; annotation to generate the boilerplate code for the Cubit.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

part of 'users_cubit.dart';

@freezed
class UsersState with _$UsersState {
  const factory UsersState.initial() = _Initial;
  const factory UsersState.loading() = _Loading;
  const factory UsersState.success(List&amp;lt;User&amp;gt; users) = _Success;
  const factory UsersState.error(String errorMessage) = _Error;

}



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After this you can run the build_runner command above,to autogenerate the methods and remove the errors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the User Cubit
&lt;/h2&gt;

&lt;p&gt;After defining all the possible states that our app can have,it's time to bring everything in order - that's what a cubit basically does.&lt;/p&gt;

&lt;p&gt;First create a UsersCubit class that extends Cubit from the bloc package:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

part 'users_state.dart';
part 'users_cubit.freezed.dart';

class UsersCubit extends Cubit&amp;lt;UsersState&amp;gt; {
  UsersCubit() : super(const UsersState.initial());
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The cubit should initally contain an instance of  UsersState.initial() passed in it's constructor, which is the initial state before the API calls begin to happen.&lt;/p&gt;

&lt;p&gt;Next,we will define a method fetchUsers() in which we will contact the API:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

    fetchUsers() async {
    try {
      emit(const UsersState.loading());
      Dio dio = Dio();

      final res = await dio.get("https://jsonplaceholder.typicode.com/users");
      if (res.statusCode == 200) {
        final users = res.data.map&amp;lt;User&amp;gt;((item) {
          return User.fromJson(item);
        }).toList();

        emit(UsersState.success(users));
      } else {
        emit(
          UsersState.error("Error loading users: ${res.data.toString()}"),
        );
      }
    } catch (e) {
      emit(
        UsersState.error("Error loading users: ${e.toString()}"),
      );
    }
  }


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;fetchUsers&lt;/code&gt; method first emits a &lt;code&gt;UsersState.loading()&lt;/code&gt; state to indicate that the user list is being loaded&lt;/li&gt;
&lt;li&gt;The Dio package is used to make an HTTP GET request to the remote API&lt;/li&gt;
&lt;li&gt;If the response status code is 200, the response data is mapped to a list of User objects using the &lt;code&gt;fromJson&lt;/code&gt; factory method of the User class. The success state is then emitted with the list of User objects.&lt;/li&gt;
&lt;li&gt;If the response status code is not 200, the error state is emitted with an error message that includes the response data.&lt;/li&gt;
&lt;li&gt;If an exception is thrown while making the HTTP request or mapping the response data, the error state is emitted with an error message that includes the exception message.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The method should be writen inside of the &lt;code&gt;UsersCubit&lt;/code&gt; class. For better and cleaner code,the API call would be separated in a repository file but let's just keep it simple for now.&lt;/p&gt;

&lt;p&gt;This is how the cubit finally looks like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

part 'users_state.dart';
part 'users_cubit.freezed.dart';

class UsersCubit extends Cubit&amp;lt;UsersState&amp;gt; {
  UsersCubit() : super(const UsersState.initial());

  fetchUsers() async {
    try {
      emit(const UsersState.loading());
      Dio dio = Dio();

      final res = await dio.get("https://jsonplaceholder.typicode.com/users");
      if (res.statusCode == 200) {
        final users = res.data.map&amp;lt;User&amp;gt;((item) {
          return User.fromJson(item);
        }).toList();

        emit(UsersState.success(users));
      } else {
        emit(
          UsersState.error("Error loading users: ${res.data.toString()}"),
        );
      }
    } catch (e) {
      emit(
        UsersState.error("Error loading users: ${e.toString()}"),
      );
    }
  }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Make sure you import all the necessary packages into the file&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the UI
&lt;/h2&gt;

&lt;p&gt;Now it's time to consume our &lt;code&gt;UsersCubit&lt;/code&gt; from the UI and show the different states as defined.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.Add BlocProvider in MaterialApp
&lt;/h3&gt;

&lt;p&gt;In the &lt;code&gt;lib/main.dart&lt;/code&gt; file at the root MyApp class,we shall have the  MaterialApp() class,whose home property will be a &lt;strong&gt;BlocProvider()&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;BlocProvider&lt;/strong&gt; takes in a &lt;code&gt;create&lt;/code&gt; function,that is responsible for creating an instance of a Cubit and a &lt;code&gt;child&lt;/code&gt; Widget which will have access to that instance through it's context.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        useMaterial3: true,
      ),
      home: BlocProvider(
        create: (context)=&amp;gt; UsersCubit(),
        child: const UsersPage(),
      ),
    );
  }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  2.Create Users page with a BlocBuilder
&lt;/h3&gt;

&lt;p&gt;We then create a Stateless Widget called &lt;code&gt;UsersPage&lt;/code&gt; in the &lt;code&gt;lib/screens/users_page.dart&lt;/code&gt; file.The page has a simple AppBar and for the body we use a BlocBuilder.&lt;/p&gt;

&lt;p&gt;BlocBuilder takes in a cubit(UsersCubit in our case) and a state(UsersState).It then handles the building of a widget in response to the cubit's current state.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

class UsersPage extends StatelessWidget {
  const UsersPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: const Text("Users"),
      ),
      body: BlocBuilder&amp;lt;UsersCubit, UsersState&amp;gt;(
        builder: (context, state) {
         //UI is built per the state
        },
      ),
    );
  }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  3.Building UI for different states.
&lt;/h3&gt;

&lt;p&gt;The builder function has a &lt;strong&gt;state.when&lt;/strong&gt; method which is used to handle the different states of the &lt;code&gt;UsersCubit&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

      body: BlocBuilder&amp;lt;UsersCubit, UsersState&amp;gt;(
        builder: (context, state) {
          return state.when(
            initial: () =&amp;gt; Center(
              child: ElevatedButton(
                child: const Text("Get Users"),
                onPressed: () =&amp;gt; context.read&amp;lt;UsersCubit&amp;gt;().fetchUsers()
              ),
            ),
            loading: () =&amp;gt; const Center(
              child: CircularProgressIndicator(),
            ),
            error: ((errorMessage) =&amp;gt; Center(child: Text(errorMessage),)),
            success: (users) {
              return ListView.builder(
                itemCount: users.length,
                itemBuilder: (context, index) {
                  return ListTile(
                    title: Text(users[index].name),
                    subtitle: Text(users[index].email),
                  );
                },
              );
            },
          );
        },
      ),


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;If the state is &lt;code&gt;initial&lt;/code&gt;, a Center widget with an ElevatedButton is returned. If the button is pressed, the &lt;code&gt;fetchUsers&lt;/code&gt; method of the &lt;code&gt;UsersCubit&lt;/code&gt; is called to load the user list.&lt;/li&gt;
&lt;li&gt;If the state is &lt;code&gt;loading&lt;/code&gt;, a Center widget with a CircularProgressIndicator is returned to indicate that the user list is being loaded.&lt;/li&gt;
&lt;li&gt;If the state is &lt;code&gt;error&lt;/code&gt;, a Center widget with a Text widget that displays the error message is returned.&lt;/li&gt;
&lt;li&gt;If the state is &lt;code&gt;success&lt;/code&gt;, a ListView.builder widget is returned to display the list of users.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With that,all the states in our cubit are taken care of effectively.&lt;br&gt;
&lt;strong&gt;&lt;em&gt;Initial State&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9a3sbfrorhm7hio8i760.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9a3sbfrorhm7hio8i760.png" alt="Initial State"&gt;&lt;/a&gt; &lt;br&gt;
&lt;strong&gt;&lt;em&gt;Loading State&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx7rfo7b3dkhd5wal27cb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx7rfo7b3dkhd5wal27cb.png" alt="Loading state"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;Success State&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffa3k2hokpvo4ph9ys5o4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffa3k2hokpvo4ph9ys5o4.png" alt="ISucess state - List of users"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;Error State&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flnjhmz0w5y7djtjuteaf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flnjhmz0w5y7djtjuteaf.png" alt="Error state"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap up
&lt;/h2&gt;

&lt;p&gt;With Cubits you just have to define your states then show the different UI's based on the current state of that cubit,that simple💯&lt;/p&gt;

&lt;p&gt;You can check the &lt;a href="https://github.com/dev-vickie/learning-cubits" rel="noopener noreferrer"&gt;Github Repo&lt;/a&gt; for the whole code.&lt;/p&gt;

&lt;p&gt;Happy Coding!&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>mobile</category>
      <category>flutterdev</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
