Search code examples
flutterdartfutureflutter-futurebuilder

Flutter: How do I get futureBuilder to feed my custom widgets data?


I made a custom feedCard widget that accepts a heading, body, and image as parameters. My understanding of the FutureBuilder is a little lacking and after countless outdated tutorials I cant seem to get a feed running properly. I haven't setup firebase yet so I'm attempting to use a preset list of data for testing purposes which I believe is the area giving me issues.

This is my feed widget:

import 'package:flutter/material.dart';
import 'package:my_app/theme.dart';
import 'package:my_app/widgets/feed_card_widget.dart';

class Feed extends StatefulWidget {
  Feed({Key? key}) : super(key: key);

  @override
  State<Feed> createState() => _FeedState();
}

class _FeedState extends State<Feed> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: backgroundColor,
      body: SafeArea(
        child: Center(
          child: Column(
            children: [
              Expanded(
                child: FutureBuilder(
                  future: _getPosts(),
                  builder: (context, AsyncSnapshot snapshot) {
                    if (snapshot.data == null) {
                      return const Center(
                        child: Text('Loading'),
                      );
                    } else {
                      return ListView.builder(
                        itemCount: snapshot.data.length,
                        itemBuilder: (context, index) {
                          return FeedCard(
                            headingText: snapshot.data[index].headingText,
                            bodyText: snapshot.data[index].bodyText,
                          );
                        },
                      );
                    }
                  },
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class Post {
  final int index;
  final String headingText;
  final String bodyText;

  Post(
    this.index,
    this.headingText,
    this.bodyText,
  );
}

List<Post> postList = <Post>[
  Post(1, 'headingText', 'bodyText'),
  Post(2, 'headingText', 'bodyText'),
  Post(3, 'headingText', 'bodyText'),
  Post(4, 'headingText', 'bodyText'),
  Post(5, 'headingText', 'bodyText'),
];

//Future function
Future<List<Post>> _getPosts() async {
  var postData = postList;

  //List being returned
  List<Post> posts = [];

  for (var p in postData) {
    Post post = Post(
      p['index'],
      p['headingText'],
      p['bodyText'],
    );
    posts.add(post);
  }

  print(posts.length);

  return posts;
}

And the trouble line of code is:

    Post post = Post(
      p['index'],
      p['headingText'],
      p['bodyText'],
    );
    posts.add(post);
  }

Solution

  • First of all, your postData is already has a type of List. But you're trying to convert it into List which is not necessary.

    • If you want your mock data to be already in List class. Just test it like this:
    import 'dart:async';
    
    Future<List<Post>> _getPosts() async {
        return Future.delayed(Duration(milliseconds: 500))
            .then((onValue) => postList);
    }
    
    • Else, if you want your mockdata to be json and convert it into List<Post>, save your mock .json file in assets/mock folder

    • then, add factory constructor to Post class

    class Post {
      final int index;
      final String headingText;
      final String bodyText;
    
      Post({
        this.index,
        this.headingText,
        this.bodyText,
      });
    
      factory Post.fromJson(Map<String, dynamic> data) {
        final index = data['index'] as int;
        final headingText = data['headingText'] as String;
        final bodyText = data['bodyText'] as String;
        return Post(index: index, headingText: headingText, bodyText: bodyText);
      }
    }
    

    then load your json file->convert it -> return it

    import 'dart:convert';
    import 'package:flutter/services.dart';
    
    Future<List<Post>> _getPosts() async {
        String response = await rootBundle.loadString('mock/your_file_name.json');
        Map<String, dynamic> parsedJson = json.decode(response);
    
        await Future.delayed(const Duration(seconds: 1));
    
        final postList = Post.fromJson(parsedJson);
    
        return postList;
      }