DEV Community

loading...
Cover image for A month of Flutter: extract post item widget

A month of Flutter: extract post item widget

abraham profile image Abraham Williams Originally published at bendyworks.com ・2 min read

Originally posted on bendyworks.com.

Yesterday I created the PostList widget to display multiple posts at once. It contained the code for rendering both the list and the individual items. As the rendering logic for the individual items is going to get more complex, I'm going to extract the item rendering code into a PostItem widget.

There aren't any feature changes in this refactor, but the PostItem lays the groundwork for adding the code to render the image, name, date, etc. That complexity should be contained within this new widget.

class PostItem extends StatelessWidget {
  const PostItem();

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Container(
        height: 300.0,
        child: const Center(
          child: Text('Prim Birb'),
        ),
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

One of the issues I see in some flutter tutorials is having widgets that are overly complex. Widgets that contain to much functionality are hard to read and test, and should be broken up into smaller widgets.

The code for PostsList is now much more concise:

class PostsList extends StatelessWidget {
  const PostsList();

  static const List<int> _items = <int>[0, 1, 2];

  @override
  Widget build(BuildContext context) {
    return ListView(children: _itemList());
  }

  List<PostItem> _itemList() {
    return _items.map((int index) => const PostItem()).toList();
  }
}
Enter fullscreen mode Exit fullscreen mode

Separating the code into multiple widgets makes unit testing easier. Tests for how a PostItem renders content can be contained within post_item_test.dart and posts_list_test.dart only has to test that PostItems are rendered.

Tests for PostItem:

testWidgets('Renders a post', (WidgetTester tester) async {
  // Build our app and trigger a frame.
  await tester.pumpWidget(const MaterialApp(
    home: PostItem(),
  ));

  expect(find.byType(Card), findsOneWidget);
  expect(find.text('Prim Birb'), findsOneWidget);
});
Enter fullscreen mode Exit fullscreen mode

Tests for PostsList:

testWidgets('Renders list of posts', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(const MaterialApp(
home: PostsList(),
));

expect(find.byType(PostItem), findsNWidgets(2));
});

Enter fullscreen mode Exit fullscreen mode




Code changes

Discussion

pic
Editor guide