fragment 0.2.2

  • README.md
  • CHANGELOG.md
  • Installing
  • Versions
  • 68

fragment #

Build Status

Prevent unnecessary build() calls in StatefulWidget and its subtrees in a readable way.

If you know React, you may consider this as a shouldComponentUpdate alternate for Flutter.

Usage #


// Add a mixin to your state and call `fragment` method in the build method of your state
class _SState extends State<S> with Fragments {
  String text;

  @override
  Widget build(BuildContext context) {
    return fragment(() {
      return Text(text); // widgets subtree to cache
    }, deps: [text]); // values used in subtree. 
    // Text() will be preserved across builds unless text is updated
  }
}

// or use `Fragment` widget 
class _SState extends State<S> {
  String text;

  @override
  Widget build(BuildContext context) {
    return Fragment((context) {
      return Text(text);
    }, deps: [text]);
    // Text() will be preserved across builds unless text is updated
  }
}

Either way, the Text widget will be cached, until text is updated to a different string.

deps accepts an Iterable, so you can declare multiple dependencies for your fragment.

API #

The library comes with a mixin Fragments an a widget Fragment.

Mixin API #

After adding Fragments mixin to your State, you will get an additional method fragment:


import 'package:fragment/fragment.dart';

// Create Widget like before 
class FragmentContainer extends StatefulWidget {
  final int key1;
  final int key2;
  final int key3;

  const FragmentContainer( {Key key, this.key1, this.key2, this.key3}) : super(key: key);

  @override
  _FragmentContainerState createState() => _FragmentContainerState();
}

// Create State with Fragments mixin
class _FragmentContainerState extends State<FragmentContainer> with Fragments {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        fragment( // use fragment method to cache a subtree
          () => Container(),
          deps: [widget.key1],
        ), 
        fragment(
          () => Container(),
          deps: [widget.key2],
        ), 
        fragment(
          () => Container(),
          deps: [widget.key3],
        ),
      ],
    );
  }
}

In the above example, when one of key1, key2 or key3 updates, the other two widgets won't be recreated.

fragment takes two parameters: a builder function which returns the cached object, and an Iterable to determine when to call the builder. During state's lifecycle, the deps parameter is contiguously compared with the previous deps from latest build. If they are shallowly equal, the previous widget is used as the return value of fragment, otherwise the builder gets called and its return value is returned by fragment and cached for future use.

All non-keyed fragment calls in the same State instance must have consistent orders across different passes of build calls, so please don't use fragment in dynamic loops and conditionals. This behavior is inspired by React hooks.

fragment also accepts an optional parameter key which accepts a Key object. Builders with the same key are excluded from the sequence of no-keyed builders. Keyed builders are not released in the state's whole lifecycle, so they can be used when a dynamic cache is needed.

Widget API #

Import and use Fragment as a widget:


import 'package:fragment/fragment.dart';

class TestFragment extends StatefulWidget {
  final Function(int) reportBuild;
  final int key1;
  final int key2;
  final int key3;

  const TestFragment(
      {Key key, this.reportBuild, this.key1, this.key2, this.key3})
      : super(key: key);

  @override
  _TestFragmentState createState() => _TestFragmentState();
}

class _TestFragmentState extends State<TestFragment> { // There's no need to add mixin
  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        Fragment(
          (context) => Container(),
          deps: [widget.key1],
        ),
        Fragment(
          (context) => Container(),
          deps: [widget.key2],
        ),
        Fragment(
          (context) => Container(),
          deps: [widget.key3],
        ),
      ],
    );
  }
}

This will give you a similar behavior like the mixin API. Since every Fragment is a normal Widget, there's no need to enforce consistent order between Fragment instances.

You can use Fragment and fragment together in the same State.

Q & A

Q:

What's the difference between the mixin API fragment and the widget API Fragment?

A:

Sadly, there's probably no prefect way to cache a widget's subtrees. Each of them have its own pros and cons.

The mixin API fragment allows you to return anything from your builder: a List, a PreferredSizeWidget, a builder function... which makes it the only way to go in some situations like caching a Material AppBar, where the parent widget Scaffold is expecting a special subtype of Widget instead of a Widget .

The widget API Fragment also has its own pros: you can use context in your builder and everything would work as expected, e.g. when you want to use InheritedModel in your subtree, the cached subtree will be rebuilt with the model, even if its corresponding deps are not changed.

TL;DR: use Fragment widget when you want to use context in your subtree, use fragment when you want to cache something other than a Widget.

Future Plans #

Add more tests.

[0.0.1]

  • Initial release.

[0.0.2]

  • Add Fragment widget.

[0.1.0]

  • Make two APIs look similar.

[0.1.2]

  • Update document.

[0.1.3]

  • Forbid context access in fragment()
  • Diff by overriding == in Fragment

[0.2.0]

  • Update interface

[0.2.1]

  • Update readme

[0.2.2]

  • Always rebuilt fragments in hot reload

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  fragment: ^0.2.2

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter packages get

Alternatively, your editor might support flutter packages get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:fragment/fragment.dart';
  
Version Uploaded Documentation Archive
0.2.2 Apr 11, 2019 Go to the documentation of fragment 0.2.2 Download fragment 0.2.2 archive
0.2.1 Apr 7, 2019 Go to the documentation of fragment 0.2.1 Download fragment 0.2.1 archive
0.2.0 Apr 7, 2019 Go to the documentation of fragment 0.2.0 Download fragment 0.2.0 archive
0.1.3 Mar 25, 2019 Go to the documentation of fragment 0.1.3 Download fragment 0.1.3 archive
0.1.2 Mar 23, 2019 Go to the documentation of fragment 0.1.2 Download fragment 0.1.2 archive
0.1.1 Mar 23, 2019 Go to the documentation of fragment 0.1.1 Download fragment 0.1.1 archive
0.1.0 Mar 23, 2019 Go to the documentation of fragment 0.1.0 Download fragment 0.1.0 archive
0.0.3 Mar 22, 2019 Go to the documentation of fragment 0.0.3 Download fragment 0.0.3 archive
0.0.2 Mar 22, 2019 Go to the documentation of fragment 0.0.2 Download fragment 0.0.2 archive
0.0.1 Mar 21, 2019 Go to the documentation of fragment 0.0.1 Download fragment 0.0.1 archive
Popularity:
Describes how popular the package is relative to other packages. [more]
41
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
90
Overall:
Weighted score of the above. [more]
68
Learn more about scoring.

We analyzed this package on Apr 22, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.2.0
  • pana: 0.12.14
  • Flutter: 1.4.7

Platforms

Detected platforms: Flutter

References Flutter, and has no conflicting libraries.

Maintenance suggestions

Maintain an example. (-10 points)

Create a short demo in the example/ directory to show how to use this package.

Common filename patterns include main.dart, example.dart, and fragment.dart. Packages with multiple examples should provide example/README.md.

For more information see the pub package layout conventions.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.1.0 <3.0.0
collection ^1.14.11 1.14.11
flutter 0.0.0
Transitive dependencies
meta 1.1.6 1.1.7
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test