# Future data

{% hint style="info" %}
**Use tip:** At first, you'll have to install **Pulse**-X package. Here's [the installation tip.](https://ye-lwin-oo-1.gitbook.io/pulse-x-state-management/pulse-x-overview/use-tip)
{% endhint %}

## Usage

Pulse-X gives you full control of Future data with **PulseXFutureViewModel**, **PulseXFutureBuilder**, **PulseXState** and **PulseXReactions**.

* **PulseXFutureViewModel** gives you features such as api handling, api data state control and business logic which are separated from U&#x49;**.**
* **PulseXFutureBuilder** makes UI reactive. It takes view model and builder function as parameters. You can show various widgets based on Future State which can be called via `viewModel.status`.&#x20;
* **PulseXState** is a simple class that has four states - **initial,loading, loaded,error**. You can control each of them.
* **PulsXeReactions** are side effects inspired from **Mobx state management.** In Pulse, you can only use side effects with Future data. 🥲

For example project, we'll use dummy data from <https://dummyjson.com>.

{% hint style="info" %}
You'll need to add `http` package in your `pubspec.yaml` file to make api requests.
{% endhint %}

First of all, create a `Post` data model.

```dart
import 'dart:convert';

Post postsFromJson(String str) => Post.fromJson(json.decode(str));

String postsToJson(Post data) => json.encode(data.toJson());

class Post {
  int id;
  String title;
  String body;
  int userId;
  List<String> tags;
  int reactions;

  Post({
    required this.id,
    required this.title,
    required this.body,
    required this.userId,
    required this.tags,
    required this.reactions,
  });

  factory Post.fromJson(Map<String, dynamic> json) => Post(
    id: json["id"],
    title: json["title"],
    body: json["body"],
    userId: json["userId"],
    tags: List<String>.from(json["tags"].map((x) => x)),
    reactions: json["reactions"],
  );

  Map<String, dynamic> toJson() => {
    "id": id,
    "title": title,
    "body": body,
    "userId": userId,
    "tags": List<dynamic>.from(tags.map((x) => x)),
    "reactions": reactions,
  };
}

```

Then, create an abstract service class so that you can easily attach, detach and switch concrete services.

```dart
import 'package:http/http.dart' as http;
import 'package:posts/model/post.dart';

const String baseUrl = 'https://dummyjson.com';

abstract class ApiService {
  final http.Client client = http.Client();
  final postUrl = Uri.parse('$baseUrl/posts');

  Future<List<Post>> getPosts();
}
```

After that, create a concrete service class that extends `ApiService` class.

```dart
const int okStatusCode = 200;
const int notFoundStatusCode = 404;

class PostService extends ApiService {
  @override
  Future<List<Post>> getPosts() async {
    try {
      http.Response res = await client.get(postUrl);
      if (res.statusCode == okStatusCode) {
        dynamic data = res.body as dynamic;
        final jsonData = jsonDecode(data);
        List<dynamic> list = jsonData['posts'] as List<dynamic>;
        List<Post> posts = [];
        for (dynamic d in list) {
          posts.add(Post.fromJson(d));
        }
        return posts;
      } else if (res.statusCode == notFoundStatusCode) {
        throw Exception('Data not found!');
      }
      throw Exception('Something went wrong!');
    } on HttpException catch (ex) {
      throw const HttpException('No internet connection!');
    } catch (ex) {
      rethrow;
    }
  }
}
```

Now, you are ready to create View Model that extends `PulseXFutureViewModel`.

<pre class="language-dart"><code class="lang-dart"><strong>class PostViewModel extends PulseXFutureViewModel {
</strong>  final ApiService service;
  PostViewModel({required this.service});
  @override
  void onInit() {
    super.onInit();
    _fetchPosts();
  }

  void _fetchPosts() async {
    changeState(PulseXState.loading()); // set state to loading
    try {
      List&#x3C;Post> posts = await service.getPosts(); // fetch data
      changeState(PulseXState.loaded(
        posts,
      )); // set state to success and pass the data
    } catch (ex) {
      changeState(PulseXState.error(ex.toString())); // set state to error and return error message
    }
  }
}

</code></pre>

In UI, you have to take care of two things - reactions and future data. First I'll extract widgets as classes to be clear.&#x20;

`ErrorMessage widget class`&#x20;

```dart
class ErrorMessage extends StatelessWidget {
  const ErrorMessage({Key? key, required this.message}) : super(key: key);
  final String message;
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text(
        message,
        style: Theme.of(context).textTheme.titleMedium?.copyWith(
          color: Colors.red.shade500,
        ),
      ),
    );
  }
}
```

Here, I'll show you one thing. If you don't wanna pass your *ViewModel* down the widget tree, Pulse-X provides you with `PulseXStateManager.of<YourViewModel>(context) method.`

`PostList widget class`

```dart
class PostList extends StatelessWidget {
  const PostList({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final viewModel = PulseXStateManager.of<PostViewModel>(context); // get your view model
    PulseXState? state = viewModel?.value;
    List<Post> posts = state?.value as List<Post>;
    return ListView.builder(
      itemCount: posts.length,
      itemBuilder: (context, index) {
        return Container(
            width: double.maxFinite,
            decoration: BoxDecoration(
              color: Colors.amber.shade200,
              borderRadius: BorderRadius.circular(8.0),
            ),
            padding: const EdgeInsets.all(
              8.0,
            ),
            margin: const EdgeInsets.symmetric(
              horizontal: 12.0,
              vertical: 6.0,
            ),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                Text(
                  posts[index].title,
                  style: Theme.of(context).textTheme.titleMedium,
                ),
                const SizedBox(height: 8),
                Text(
                  posts[index].body,
                  style: Theme.of(context).textTheme.bodyMedium,
                  maxLines: 3,
                  overflow: TextOverflow.ellipsis,
                ),
              ],
            ));
      },
    );
  }
}
```

Then, show data based on your state.

<pre class="language-dart"><code class="lang-dart"><strong>class PostView extends StatefulWidget {
</strong>  const PostView({Key? key}) : super(key: key);

  @override
  State&#x3C;PostView> createState() => _PostViewState();
}

class _PostViewState extends State&#x3C;PostView> {
  final postViewModel = PostViewModel(service: PostService()); // initialize your view model
  late PulseXReaction reaction;

@override
  void didChangeDependencies() {
    super.didChangeDependencies();
    // TODO: add your reaction here!
  }
  
  @override
  void dispose() {
    reaction.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Posts'),
      ),
      body: PulseFutureBuilder(
        viewModel: postViewModel,
        builder: (_, PulseXState&#x3C;dynamic> state, __) {
          if (state.status == PulseXStatus.error) { // error state
            return ErrorMessage(message: '${state.message}');
          } else if (state.status == PulseXStatus.loaded) { // loaded state
            return const PostList();
          }
          return const Center( // loading or initial state
            child: CupertinoActivityIndicator(
              radius: 20,
              color: Colors.amber,
            ),
          );
        },
      ),
    );
  }
}
</code></pre>

As the last step, you only need to create a reaction based on state. If state is loaded, then show a snackbar.

Remove `TODO`and add this in your `didChangeDependencies()` method.

```dart
reaction = PulseXReaction(postViewModel, (value, dispose) {
      if (value.status == PulseXStatus.loaded) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Center(
              child: Text(
                '🥳 Hooray!!, Posts have been loaded!',
                style: Theme.of(context).textTheme.bodyLarge?.copyWith(
                  color: Colors.indigo,
                ),
              ),
            ),
            backgroundColor: Colors.indigo.shade100,
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(16.0),
            ),
            padding: const EdgeInsets.symmetric(
              vertical: 14.0,
              horizontal: 8.0,
            ),
            margin: const EdgeInsets.symmetric(
              horizontal: 14.0,
              vertical: 10.0,
            ),
            behavior: SnackBarBehavior.floating,
            showCloseIcon: true,
          ),
        );
      }
    });
```

👏🏻 Tada! Now, you understand how pulse works and will be able to use it in your projects.

{% hint style="success" %}
Complete source code can be found here. <https://github.com/YeLwinOo-Steve/posts>
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ye-lwin-oo-1.gitbook.io/pulse-x-state-management/state-management/future-data.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
