• Stars
    star
    774
  • Rank 58,703 (Top 2 %)
  • Language
    Dart
  • License
    BSD 3-Clause "New...
  • Created almost 7 years ago
  • Updated 3 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A Widget that passes a Reactive Model to all of it's children

scoped_model

Build Status codecov

A set of utilities that allow you to easily pass a data Model from a parent Widget down to its descendants. In addition, it also rebuilds all of the children that use the model when the model is updated. This library was originally extracted from the Fuchsia codebase.

This Library provides three main classes:

  • The Model class. You will extend this class to create your own Models, such as SearchModel or UserModel. You can listen to Models for changes!
  • The ScopedModel Widget. If you need to pass a Model deep down your Widget hierarchy, you can wrap your Model in a ScopedModel Widget. This will make the Model available to all descendant Widgets.
  • The ScopedModelDescendant Widget. Use this Widget to find the appropriate ScopedModel in the Widget tree. It will automatically rebuild whenever the Model notifies that change has taken place.

This library is built upon several features of Flutter:

  • The Model class implements the Listenable interface
    • AnimationController and TextEditingController are also Listenables
  • The Model is passed down the Widget tree using an InheritedWidget. When an InheritedWidget is rebuilt, it will surgically rebuild all of the Widgets that depend on its data. No need to manage subscriptions!
  • It uses the AnimatedBuilder Widget under the hood to listen to the Model and rebuild the InheritedWidget when the model changes.

Examples

  • Counter App - Introduction to the tools provided by Scoped Model.
  • Todo App - Shows how to write a Todo app with persistence and tests.

Usage

Let's demo the basic usage with the all-time favorite: A counter example!

// Start by creating a class that holds some view the app's state. In
// our example, we'll have a simple counter that starts at 0 can be 
// incremented.
//
// Note: It must extend from Model.  
class CounterModel extends Model {
  int _counter = 0;

  int get counter => _counter;

  void increment() {
    // First, increment the counter
    _counter++;
    
    // Then notify all the listeners.
    notifyListeners();
  }
}

// Create our App, which will provide the `CounterModel` to 
// all children that require it! 
class CounterApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // First, create a `ScopedModel` widget. This will provide 
    // the `model` to the children that request it. 
    return new ScopedModel<CounterModel>(
      model: new CounterModel(),
      child: new Column(children: [
        // Create a ScopedModelDescendant. This widget will get the
        // CounterModel from the nearest ScopedModel<CounterModel>. 
        // It will hand that model to our builder method, and rebuild 
        // any time the CounterModel changes (i.e. after we 
        // `notifyListeners` in the Model). 
        new ScopedModelDescendant<CounterModel>(
          builder: (context, child, model) => new Text('${model.counter}'),
        ),
        new Text("Another widget that doesn't depend on the CounterModel")
      ])
    );
  }
}

Finding the Model

There are two ways to find the Model provided by the ScopedModel Widget.

  1. Use the ScopedModelDescendant Widget. It will find the Model and run the builder function whenever the Model notifies the listeners.
  2. Use the ScopedModel.of static method directly. To make this method more readable for frequent access, you can consider adding your own of method to your own Model classes like so:
class CounterModel extends Model {
  // ...
 
  /// Wraps [ScopedModel.of] for this [Model].
  static CounterModel of(BuildContext context) =>
      ScopedModel.of<CounterModel>(context);
}

Listening to multiple Models in a build function

In many cases, it makes sense to split your Models apart into logical components by functionality. For example, rather than having an AppModel that contains all of your application logic, it can often make more sense to split models apart into a UserModel, a SearchModel and a ProductModel, for example.

However, if you need to display information from two of these models in a single Widget, you might be wondering how to achieve that! To do so, you have two options:

  1. Use multiple ScopedModelDescendant Widgets
  2. Use multiple ScopedModel.of calls. No need to manage subscriptions, Flutter takes care of all of that through the magic of InheritedWidgets.
class CombinedWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final username =
      ScopedModel.of<UserModel>(context, rebuildOnChange: true).username;
    final counter =
      ScopedModel.of<CounterModel>(context, rebuildOnChange: true).counter;

    return Text('$username tapped the button $counter times');
  }
}

Contributors

More Repositories

1

flutter_architecture_samples

TodoMVC for Flutter
Dart
8,720
star
2

flutter_redux

A library that connects Widgets to a Redux Store
Dart
1,648
star
3

bansa

A state container for Java & Kotlin, inspired by Redux & Elm
Kotlin
442
star
4

flutter_stetho

Integrate Flutter with the Facebook Stetho tool for Android
Dart
219
star
5

dart_redux_epics

Redux.dart middleware for handling actions using Dart Streams
Dart
141
star
6

new_flutter_template

Test ideas for a new flutter template
Dart
140
star
7

transparent_image

A transparent image in Dart code, represented as a Uint8List.
Dart
103
star
8

redux_thunk

Redux Middleware for handling functions as actions
Dart
88
star
9

github_search_angular_flutter

Demonstrates how to use the bloc pattern for both an Angular and Flutter app
CSS
85
star
10

flutter_stream_friends

Flutter's great. Streams are great. Let's be friends.
Dart
62
star
11

gradient_animations

An example of how to animate gradients in flutter
Dart
61
star
12

flutter_redux_dev_tools

A Time Traveling Redux Debugger for Flutter
Makefile
40
star
13

reselect_dart

Efficiently derive data from your Redux Store
Dart
37
star
14

redux_logging

Redux.dart Middleware that prints the latest action & state
Dart
30
star
15

rainbow_gradient

An easy way to add Rainbows to your Flutter apps!
Dart
23
star
16

giphy_client

A Giphy API Client for Dart compatible with all platforms
Dart
22
star
17

mvi_sealed_unions

dart_sealed_union playground, started with code from Flutter Consortium
Dart
21
star
18

memory_image_converter

A command line app that will convert an image into a Uint8List which can be consumed by a Flutter app using the `MemoryImage`, `Image.memory`, or `FadeInImage.memoryNetwork` classes.
Dart
16
star
19

hacker_news_client

A client for the Hacker News API. Works on Flutter, Server, and Web.
Dart
16
star
20

hnpwa_client

Fetch data from the HNPWA API -- a Hacker News API crafted for mobile and progressive web apps
Dart
14
star
21

open_iconic_flutter

The Open Iconic icon pack available as a set of Flutter Icons
Dart
14
star
22

rxdart_codemod

A collection of codemods to upgrade your RxDart code from one version to the next
Dart
11
star
23

redux_future

A Redux Middleware for handling Dart Futures as actions
Dart
10
star
24

draggable_scrollbar

A scrollbar that can be used to quickly navigate through a list
Dart
10
star
25

fancy_network_image

A port of cached_network_image all the goodies EXCEPT the cache
Dart
10
star
26

scoped_model_github_search

Translated the RxDart Github Search example to ScopedModel
Dart
9
star
27

redux_dev_tools

Time Travel Dev Tools for Dart Redux
Dart
8
star
28

CSScaffold.tmbundle

Like or want to learn CSScaffold, but tired of referring to the documentation or looking through Mixins.css files? Use the the Textmate bundle!
6
star
29

flutter_lcov_docker

Flutter + Lcov for code Coverage reports!
5
star
30

swapi_client

A library that makes it easy to fetch data from SWAPI: The Star Wars API.
Dart
5
star
31

workshop_live_coding_login

Dart
4
star
32

nested_bottom_navigation

A test of how to do nested bottom navigation with BottomNavigation
Dart
4
star
33

flutter_ui_challenge_zoom_menu

Flutter UI Challenge: Zoom Menu.
Dart
3
star
34

dotfiles

The dotfiles of Brian Egan
HTML
3
star
35

stream_store

A Redux-style Store implemented using core Dart Stream primitives
Dart
3
star
36

hacker_news_app

Hacker news app for flutter
Dart
3
star
37

ez_listenable

A set utilities that allow you to listen to objects and notify listeners of changes
CSS
3
star
38

dribbble_client

A Dribbble api client for Dart
Dart
3
star
39

monocle

View CONTENTdm images with style!
JavaScript
2
star
40

Scaffold.ruble

Aptana Bundle for the Scaffold CSS preprocessor!
Ruby
2
star
41

Playduino

JavaScript
2
star
42

Vim-Configuration

My personal vim folder!
Vim Script
1
star
43

BangumiList

萌豚 番剧清单
Dart
1
star
44

loadTest.js

A simple load test script for phantomjs
1
star
45

dmsuggest

A Search Suggestion App for dmBridge
JavaScript
1
star
46

HotTest

The hottest way to run client-side unit tests
JavaScript
1
star
47

pic_in_a_box

A swank replica of Sexy Slider.
JavaScript
1
star
48

Dilefont

Such a dilettante
JavaScript
1
star
49

transmit-vim

Integrates Transmit FTP (Mac) with Vim
Vim Script
1
star
50

dmcarousel

A slideshow application for dmBridge
JavaScript
1
star