SlideShare a Scribd company logo
InheritedWidget
is your friend
Andrea Bizzotto
codingwithflutter.com @biz84
GDG London 08-08-2018
Get access to stuff
Networking
Authentication
Database
Secure Storage
FileSystem
Get access to stuff
🌍 Global Access

🌗 Dependency Injection

🌝 Scoped Access
Example
Get access to stuff
🌍 Global Access

🌗 Dependency Injection

🌝 Scoped Access
import 'package:firebase_auth/firebase_auth.dart';
class LoginPage extends StatelessWidget {
LoginPage({this.onSignedIn});
final VoidCallback onSignedIn;
void signInUser(String email, String password) async {
try {
await FirebaseAuth.instance.signInWithEmailAndPassword(
email: email, password: password);
onSignedIn();
} catch (e) {
// Sign in failed: show error to user
}
}
}
Global Access
import 'package:firebase_auth/firebase_auth.dart';
class LoginPage extends StatelessWidget {
LoginPage({this.onSignedIn});
final VoidCallback onSignedIn;
void signInUser(String email, String password) async {
try {
await FirebaseAuth.instance.signInWithEmailAndPassword(
email: email, password: password);
onSignedIn();
} catch (e) {
// Sign in failed: show error to user
}
}
}
Global Access
import 'package:firebase_auth/firebase_auth.dart';
class LoginPage extends StatelessWidget {
LoginPage({this.onSignedIn});
final VoidCallback onSignedIn;
void signInUser(String email, String password) async {
try {
await FirebaseAuth.instance.signInWithEmailAndPassword(
email: email, password: password);
onSignedIn();
} catch (e) {
// Sign in failed: show error to user
}
}
}
Global Access
import 'package:firebase_auth/firebase_auth.dart';
class LoginPage extends StatelessWidget {
LoginPage({this.onSignedIn});
final VoidCallback onSignedIn;
void signInUser(String email, String password) async {
try {
await FirebaseAuth.instance.signInWithEmailAndPassword(
email: email, password: password);
onSignedIn();
} catch (e) {
// Sign in failed: show error to user
}
}
}
Global Access
import 'package:firebase_auth/firebase_auth.dart';
class LoginPage extends StatelessWidget {
LoginPage({this.onSignedIn});
final VoidCallback onSignedIn;
void signInUser(String email, String password) async {
try {
await FirebaseAuth.instance.signInWithEmailAndPassword(
email: email, password: password);
onSignedIn();
} catch (e) {
// Sign in failed: show error to user
}
}
}
Global Access
Global Access
😀 Very little code

🙁 Tight Coupling

🙁 Hard to test

😱 Singletons everywhere
Global Access
Global Access
Global Access
Ask
Access
🌍 Global Access

🌗 Dependency Injection

🌝 Scoped Access
Dependency Injection
Tell
Dependency Injection
import ‘package:login_demo/auth.dart’;
class LoginPage extends StatelessWidget {
LoginPage({this.auth, this.onSignedIn});
final Auth auth;
final VoidCallback onSignedIn;
void signInUser(String email, String password) async {
try {
await auth.signInWithEmailAndPassword(
email: email, password: password);
onSignedIn();
} catch (e) {
// Sign in failed: show error to user
}
}
}
Dependency Injection
import ‘package:login_demo/auth.dart’;
class LoginPage extends StatelessWidget {
LoginPage({this.auth, this.onSignedIn});
final Auth auth;
final VoidCallback onSignedIn;
void signInUser(String email, String password) async {
try {
await auth.signInWithEmailAndPassword(
email: email, password: password);
onSignedIn();
} catch (e) {
// Sign in failed: show error to user
}
}
}
Dependency Injection
Tell
Dependency Injection
Dependency Injection
🙃 A bit more boilerplate

🙂 Tell, don’t ask

🎉 Easy to test
Photo by Adam Whitlock on Unsplash
🙃 A bit more boilerplate

🙂 Tell, don’t ask

🎉 Easy to test

😒 Plumbing
Dependency Injection
A third way?
🌍 Global access

🌗 Dependency injection

🌝 Scoped access
InheritedWidget
InheritedWidget
InheritedWidget
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (BuildContext context) {
return SomePage();
},
));
Theme.of(context).primaryColor
import 'package:login_demo/auth_provider.dart';
class LoginPage extends StatelessWidget {
LoginPage({this.onSignedIn});
final VoidCallback onSignedIn;
void signInUser(String email, String password) async {
try {
final auth = AuthProvider.of(context).auth;
await auth.signInWithEmailAndPassword(
email: email, password: password);
onSignedIn();
} catch (e) {
// Sign in failed: show error to user
}
}
}
InheritedWidget
import 'package:login_demo/auth_provider.dart';
class LoginPage extends StatelessWidget {
LoginPage({this.onSignedIn});
final VoidCallback onSignedIn;
void signInUser(String email, String password) async {
try {
final auth = AuthProvider.of(context).auth;
await auth.signInWithEmailAndPassword(
email: email, password: password);
onSignedIn();
} catch (e) {
// Sign in failed: show error to user
}
}
}
InheritedWidget
InheritedWidget

making your own
class AuthProvider extends InheritedWidget {
AuthProvider({Key key, Widget child, this.auth}) :
super(key: key, child: child);
final Auth auth;
@override
bool updateShouldNotify(InheritedWidget oldWidget) => true;
static AuthProvider of(BuildContext context) {
return context.inheritFromWidgetOfExactType(AuthProvider);
}
}
InheritedWidget
class AuthProvider extends InheritedWidget {
AuthProvider({Key key, Widget child, this.auth}) :
super(key: key, child: child);
final Auth auth;
@override
bool updateShouldNotify(InheritedWidget oldWidget) => true;
static AuthProvider of(BuildContext context) {
return context.inheritFromWidgetOfExactType(AuthProvider);
}
}
InheritedWidget
class AuthProvider extends InheritedWidget {
AuthProvider({Key key, Widget child, this.auth}) :
super(key: key, child: child);
final Auth auth;
@override
bool updateShouldNotify(InheritedWidget oldWidget) => true;
static AuthProvider of(BuildContext context) {
return context.inheritFromWidgetOfExactType(AuthProvider);
}
}
InheritedWidget
class AuthProvider extends InheritedWidget {
AuthProvider({Key key, Widget child, this.auth}) :
super(key: key, child: child);
final Auth auth;
@override
bool updateShouldNotify(InheritedWidget oldWidget) => true;
static AuthProvider of(BuildContext context) {
return context.inheritFromWidgetOfExactType(AuthProvider);
}
}
InheritedWidget
class AuthProvider extends InheritedWidget {
AuthProvider({Key key, Widget child, this.auth}) :
super(key: key, child: child);
final Auth auth;
@override
bool updateShouldNotify(InheritedWidget oldWidget) => true;
static AuthProvider of(BuildContext context) {
return context.inheritFromWidgetOfExactType(AuthProvider);
}
}
InheritedWidget
class AuthProvider extends InheritedWidget {
AuthProvider({Key key, Widget child, this.auth}) :
super(key: key, child: child);
final Auth auth;
@override
bool updateShouldNotify(InheritedWidget oldWidget) => true;
static AuthProvider of(BuildContext context) {
return context.inheritFromWidgetOfExactType(AuthProvider);
}
}
InheritedWidget
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AuthProvider(
auth: Auth(),
child: MaterialApp(
title: 'Flutter login demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: RootPage(),
),
);
}
}
InheritedWidget
InheritedWidget
😐 Some boilerplate code

😀 Easy to test

😀 Easy to maintain 

🧐 Tradeoffs
InheritedWidget

tradeoffs?
• Class.of(context) shouldn’t be called from
initState()

• Use didChangeDependencies() instead.

• ⚠ called more than once!
InheritedWidget

tradeoffs?
StatefulWidget
abstract class Database {
Future<void> addTweet(Tweet tweet);
Stream<List<Tweet>> tweetsStream();
}
class AppDatabase implements Database {
AppDatabase({this.userId});
final String userId;
Future<void> addTweet(Tweet tweet) {
...
}
Stream<List<Tweet>> tweetsStream() {
...
}
}
Twitter Client
users/$userId/tweets
abstract class Database {
Future<void> addTweet(Tweet tweet);
Stream<List<Tweet>> tweetsStream();
}
class AppDatabase implements Database {
AppDatabase({this.userId});
final String userId;
Future<void> addTweet(Tweet tweet) {
...
}
Stream<List<Tweet>> tweetsStream() {
...
}
}
Twitter Client
users/$userId/tweets
abstract class Database {
Future<void> addTweet(Tweet tweet);
Stream<List<Tweet>> tweetsStream();
}
class AppDatabase implements Database {
AppDatabase({this.userId});
final String userId;
Future<void> addTweet(Tweet tweet) {
...
}
Stream<List<Tweet>> tweetsStream() {
...
}
}
Twitter Client
users/$userId/tweets
abstract class Database {
String userId;
Future<void> addTweet(Tweet tweet);
Stream<List<Tweet>> tweetsStream();
}
class AppDatabase implements Database {
Future<void> addTweet(Tweet tweet) {
...
}
Stream<List<Tweet>> tweetsStream() {
...
}
}
class ServiceProvider implements InheritedWidget {
ServiceProvider({Widget child, this.auth, this.database});
final BaseAuth auth;
final Database database;
}
Twitter Client
users/$userId/tweets
abstract class Database {
String userId;
Future<void> addTweet(Tweet tweet);
Stream<List<Tweet>> tweetsStream();
}
class AppDatabase implements Database {
Future<void> addTweet(Tweet tweet) {
assert(userId != null);
}
Stream<List<Tweet>> tweetsStream() {
assert(userId != null);
}
}
class ServiceProvider implements InheritedWidget {
ServiceProvider({Widget child, this.auth, this.database});
final BaseAuth auth;
final Database database;
}
Twitter Client
users/$userId/tweets
abstract class Database {
Future<void> addTweet(Tweet tweet);
Stream<List<Tweet>> tweetsStream();
}
class AppDatabase implements Database {
AppDatabase({this.userId});
final String userId;
Future<void> addTweet(Tweet tweet) {
...
}
Stream<List<Tweet>> tweetsStream() {
...
}
}
class DatabaseProvider implements InheritedWidget {
DatabaseProvider({Widget child, this.database});
final Database database;
}
Twitter Client
users/$userId/tweets
class Provider<T> extends InheritedWidget
InheritedWidget

multiple providers?
💡
• AuthProvider

• DatabaseProvider

• …
class Provider<T> extends InheritedWidget {
Provider({Key key, Widget child, this.object})
: super(key: key, child: child);
final T object;
@override
bool updateShouldNotify(InheritedWidget oldWidget) => true;
static T of<T>(BuildContext context) {
final type = _typeOf<Provider<T>>();
Provider<T> provider = context
.inheritFromWidgetOfExactType(type);
return provider.object;
}
static Type _typeOf<T>() => T;
}
InheritedWidget
InheritedWidget all the things!
Get access to stuff
🌍 Global Access

🌗 Dependency Injection

🌝 Scoped Access
Get access to stuff
Code required Testing Maintainability
Global

Access 😀 😭 😭
Dependency

Injection 🙂 😀 🙁
Scoped

Access 😐 😀 😀
*Your mileage may vary
Get access to stuff
🌍 Global Access

🌗 Dependency Injection

🌝 Scoped Access

🤓 Service Locator
Service Locator
https://pub.dartlang.org/packages/get_it
THANK YOU
codingwithflutter.com @biz84
Login Demo [GitHub]
Widget — State — BuildContext — InheritedWidget

More Related Content

What's hot

2020-02-20 - HashiCorpUserGroup Madring - Integrating HashiCorp Vault and Kub...
2020-02-20 - HashiCorpUserGroup Madring - Integrating HashiCorp Vault and Kub...2020-02-20 - HashiCorpUserGroup Madring - Integrating HashiCorp Vault and Kub...
2020-02-20 - HashiCorpUserGroup Madring - Integrating HashiCorp Vault and Kub...
Andrey Devyatkin
 
Basic Tutorial of React for Programmers
Basic Tutorial of React for ProgrammersBasic Tutorial of React for Programmers
Basic Tutorial of React for Programmers
David Rodenas
 
Introduction to jQuery
Introduction to jQueryIntroduction to jQuery
Introduction to jQuery
Nagaraju Sangam
 
How to build twitter bot using golang from scratch
How to build twitter bot using golang from scratchHow to build twitter bot using golang from scratch
How to build twitter bot using golang from scratch
Katy Slemon
 
UA Testing with Selenium and PHPUnit - ZendCon 2013
UA Testing with Selenium and PHPUnit - ZendCon 2013UA Testing with Selenium and PHPUnit - ZendCon 2013
UA Testing with Selenium and PHPUnit - ZendCon 2013
Michelangelo van Dam
 
JSON Rules Language
JSON Rules LanguageJSON Rules Language
JSON Rules Language
giurca
 
Better Bullshit Driven Development [SeleniumCamp 2017]
Better Bullshit Driven Development [SeleniumCamp 2017]Better Bullshit Driven Development [SeleniumCamp 2017]
Better Bullshit Driven Development [SeleniumCamp 2017]
automician
 
What the Struts?
What the Struts?What the Struts?
What the Struts?
Joe Kutner
 
Visual Component Testing -- w/ Gil Tayar (Applitools) and Gleb Bahmutov (Cyp...
Visual Component Testing  -- w/ Gil Tayar (Applitools) and Gleb Bahmutov (Cyp...Visual Component Testing  -- w/ Gil Tayar (Applitools) and Gleb Bahmutov (Cyp...
Visual Component Testing -- w/ Gil Tayar (Applitools) and Gleb Bahmutov (Cyp...
Applitools
 
Frontends w ithout javascript
Frontends w ithout javascriptFrontends w ithout javascript
Frontends w ithout javascript
Stephen Lorello
 
What the heck went wrong?
What the heck went wrong?What the heck went wrong?
What the heck went wrong?
Andy McKay
 
Implementing security routines with zf2
Implementing security routines with zf2Implementing security routines with zf2
Implementing security routines with zf2
Er Galvão Abbott
 
HTML5 Web Messaging
HTML5 Web MessagingHTML5 Web Messaging
HTML5 Web Messaging
Mike Taylor
 
Authentication with zend framework
Authentication with zend frameworkAuthentication with zend framework
Authentication with zend framework
George Mihailov
 
Nk API - examples
Nk API - examplesNk API - examples
Nk API - examples
nasza-klasa
 
WCLA12 JavaScript
WCLA12 JavaScriptWCLA12 JavaScript
WCLA12 JavaScript
Jeffrey Zinn
 
Sperimentazioni lezione6 from_designtoapplication copy
Sperimentazioni lezione6 from_designtoapplication copySperimentazioni lezione6 from_designtoapplication copy
Sperimentazioni lezione6 from_designtoapplication copy
Salvatore Iaconesi
 
Android ui layouts ,cntls,webservices examples codes
Android ui layouts ,cntls,webservices examples codesAndroid ui layouts ,cntls,webservices examples codes
Android ui layouts ,cntls,webservices examples codes
Aravindharamanan S
 
jQuery : Events are where it happens!
jQuery : Events are where it happens!jQuery : Events are where it happens!
jQuery : Events are where it happens!
Wildan Maulana
 
jQuery Bay Area Conference 2010
jQuery Bay Area Conference 2010jQuery Bay Area Conference 2010
jQuery Bay Area Conference 2010
mennovanslooten
 

What's hot (20)

2020-02-20 - HashiCorpUserGroup Madring - Integrating HashiCorp Vault and Kub...
2020-02-20 - HashiCorpUserGroup Madring - Integrating HashiCorp Vault and Kub...2020-02-20 - HashiCorpUserGroup Madring - Integrating HashiCorp Vault and Kub...
2020-02-20 - HashiCorpUserGroup Madring - Integrating HashiCorp Vault and Kub...
 
Basic Tutorial of React for Programmers
Basic Tutorial of React for ProgrammersBasic Tutorial of React for Programmers
Basic Tutorial of React for Programmers
 
Introduction to jQuery
Introduction to jQueryIntroduction to jQuery
Introduction to jQuery
 
How to build twitter bot using golang from scratch
How to build twitter bot using golang from scratchHow to build twitter bot using golang from scratch
How to build twitter bot using golang from scratch
 
UA Testing with Selenium and PHPUnit - ZendCon 2013
UA Testing with Selenium and PHPUnit - ZendCon 2013UA Testing with Selenium and PHPUnit - ZendCon 2013
UA Testing with Selenium and PHPUnit - ZendCon 2013
 
JSON Rules Language
JSON Rules LanguageJSON Rules Language
JSON Rules Language
 
Better Bullshit Driven Development [SeleniumCamp 2017]
Better Bullshit Driven Development [SeleniumCamp 2017]Better Bullshit Driven Development [SeleniumCamp 2017]
Better Bullshit Driven Development [SeleniumCamp 2017]
 
What the Struts?
What the Struts?What the Struts?
What the Struts?
 
Visual Component Testing -- w/ Gil Tayar (Applitools) and Gleb Bahmutov (Cyp...
Visual Component Testing  -- w/ Gil Tayar (Applitools) and Gleb Bahmutov (Cyp...Visual Component Testing  -- w/ Gil Tayar (Applitools) and Gleb Bahmutov (Cyp...
Visual Component Testing -- w/ Gil Tayar (Applitools) and Gleb Bahmutov (Cyp...
 
Frontends w ithout javascript
Frontends w ithout javascriptFrontends w ithout javascript
Frontends w ithout javascript
 
What the heck went wrong?
What the heck went wrong?What the heck went wrong?
What the heck went wrong?
 
Implementing security routines with zf2
Implementing security routines with zf2Implementing security routines with zf2
Implementing security routines with zf2
 
HTML5 Web Messaging
HTML5 Web MessagingHTML5 Web Messaging
HTML5 Web Messaging
 
Authentication with zend framework
Authentication with zend frameworkAuthentication with zend framework
Authentication with zend framework
 
Nk API - examples
Nk API - examplesNk API - examples
Nk API - examples
 
WCLA12 JavaScript
WCLA12 JavaScriptWCLA12 JavaScript
WCLA12 JavaScript
 
Sperimentazioni lezione6 from_designtoapplication copy
Sperimentazioni lezione6 from_designtoapplication copySperimentazioni lezione6 from_designtoapplication copy
Sperimentazioni lezione6 from_designtoapplication copy
 
Android ui layouts ,cntls,webservices examples codes
Android ui layouts ,cntls,webservices examples codesAndroid ui layouts ,cntls,webservices examples codes
Android ui layouts ,cntls,webservices examples codes
 
jQuery : Events are where it happens!
jQuery : Events are where it happens!jQuery : Events are where it happens!
jQuery : Events are where it happens!
 
jQuery Bay Area Conference 2010
jQuery Bay Area Conference 2010jQuery Bay Area Conference 2010
jQuery Bay Area Conference 2010
 

Similar to InheritedWidget is your friend - GDG London (2018-08-08)

Geb qa fest2017
Geb qa fest2017Geb qa fest2017
Geb qa fest2017
Sviatkin Yaroslav
 
Jug Guice Presentation
Jug Guice PresentationJug Guice Presentation
Jug Guice Presentation
Dmitry Buzdin
 
Connecting to a Webservice.pdf
Connecting to a Webservice.pdfConnecting to a Webservice.pdf
Connecting to a Webservice.pdf
ShaiAlmog1
 
AuthN deep.dive—ASP.NET Authentication Internals.pdf
AuthN deep.dive—ASP.NET Authentication Internals.pdfAuthN deep.dive—ASP.NET Authentication Internals.pdf
AuthN deep.dive—ASP.NET Authentication Internals.pdf
ondrejl1
 
DRYing to Monad in Java8
DRYing to Monad in Java8DRYing to Monad in Java8
DRYing to Monad in Java8
Dhaval Dalal
 
Building @Anywhere (for TXJS)
Building @Anywhere (for TXJS)Building @Anywhere (for TXJS)
Building @Anywhere (for TXJS)
danwrong
 
Creating a Facebook Clone - Part XXV.pdf
Creating a Facebook Clone - Part XXV.pdfCreating a Facebook Clone - Part XXV.pdf
Creating a Facebook Clone - Part XXV.pdf
ShaiAlmog1
 
A test framework out of the box - Geb for Web and mobile
A test framework out of the box - Geb for Web and mobileA test framework out of the box - Geb for Web and mobile
A test framework out of the box - Geb for Web and mobile
GlobalLogic Ukraine
 
Creating a Facebook Clone - Part XLV.pdf
Creating a Facebook Clone - Part XLV.pdfCreating a Facebook Clone - Part XLV.pdf
Creating a Facebook Clone - Part XLV.pdf
ShaiAlmog1
 
QA Fest 2017. Ярослав Святкин. Тестовый фреймворк GEB для тестирования WEB пр...
QA Fest 2017. Ярослав Святкин. Тестовый фреймворк GEB для тестирования WEB пр...QA Fest 2017. Ярослав Святкин. Тестовый фреймворк GEB для тестирования WEB пр...
QA Fest 2017. Ярослав Святкин. Тестовый фреймворк GEB для тестирования WEB пр...
QAFest
 
JavaCro'14 - Building interactive web applications with Vaadin – Peter Lehto
JavaCro'14 - Building interactive web applications with Vaadin – Peter LehtoJavaCro'14 - Building interactive web applications with Vaadin – Peter Lehto
JavaCro'14 - Building interactive web applications with Vaadin – Peter Lehto
HUJAK - Hrvatska udruga Java korisnika / Croatian Java User Association
 
From 0 to Spring Security 4.0
From 0 to Spring Security 4.0From 0 to Spring Security 4.0
From 0 to Spring Security 4.0
robwinch
 
Vue JS @ MindDoc. The progressive road to online therapy
Vue JS @ MindDoc. The progressive road to online therapyVue JS @ MindDoc. The progressive road to online therapy
Vue JS @ MindDoc. The progressive road to online therapy
Darío Blanco Iturriaga
 
React native-firebase startup-mtup
React native-firebase startup-mtupReact native-firebase startup-mtup
React native-firebase startup-mtup
t k
 
Google Web Toolkits
Google Web ToolkitsGoogle Web Toolkits
Google Web Toolkits
Yiguang Hu
 
Webauthn Tutorial
Webauthn TutorialWebauthn Tutorial
Webauthn Tutorial
FIDO Alliance
 
Creating a Facebook Clone - Part XXV - Transcript.pdf
Creating a Facebook Clone - Part XXV - Transcript.pdfCreating a Facebook Clone - Part XXV - Transcript.pdf
Creating a Facebook Clone - Part XXV - Transcript.pdf
ShaiAlmog1
 
Building the an End-to-End ASP.NET MVC 4, Entity Framework, HTML5, jQuery app...
Building the an End-to-End ASP.NET MVC 4, Entity Framework, HTML5, jQuery app...Building the an End-to-End ASP.NET MVC 4, Entity Framework, HTML5, jQuery app...
Building the an End-to-End ASP.NET MVC 4, Entity Framework, HTML5, jQuery app...
Dan Wahlin
 
Building Persona: federated and privacy-sensitive identity for the Web (Open ...
Building Persona: federated and privacy-sensitive identity for the Web (Open ...Building Persona: federated and privacy-sensitive identity for the Web (Open ...
Building Persona: federated and privacy-sensitive identity for the Web (Open ...
Francois Marier
 
Cutting edge HTML5 API you can use today (by Bohdan Rusinka)
 Cutting edge HTML5 API you can use today (by Bohdan Rusinka) Cutting edge HTML5 API you can use today (by Bohdan Rusinka)
Cutting edge HTML5 API you can use today (by Bohdan Rusinka)
Binary Studio
 

Similar to InheritedWidget is your friend - GDG London (2018-08-08) (20)

Geb qa fest2017
Geb qa fest2017Geb qa fest2017
Geb qa fest2017
 
Jug Guice Presentation
Jug Guice PresentationJug Guice Presentation
Jug Guice Presentation
 
Connecting to a Webservice.pdf
Connecting to a Webservice.pdfConnecting to a Webservice.pdf
Connecting to a Webservice.pdf
 
AuthN deep.dive—ASP.NET Authentication Internals.pdf
AuthN deep.dive—ASP.NET Authentication Internals.pdfAuthN deep.dive—ASP.NET Authentication Internals.pdf
AuthN deep.dive—ASP.NET Authentication Internals.pdf
 
DRYing to Monad in Java8
DRYing to Monad in Java8DRYing to Monad in Java8
DRYing to Monad in Java8
 
Building @Anywhere (for TXJS)
Building @Anywhere (for TXJS)Building @Anywhere (for TXJS)
Building @Anywhere (for TXJS)
 
Creating a Facebook Clone - Part XXV.pdf
Creating a Facebook Clone - Part XXV.pdfCreating a Facebook Clone - Part XXV.pdf
Creating a Facebook Clone - Part XXV.pdf
 
A test framework out of the box - Geb for Web and mobile
A test framework out of the box - Geb for Web and mobileA test framework out of the box - Geb for Web and mobile
A test framework out of the box - Geb for Web and mobile
 
Creating a Facebook Clone - Part XLV.pdf
Creating a Facebook Clone - Part XLV.pdfCreating a Facebook Clone - Part XLV.pdf
Creating a Facebook Clone - Part XLV.pdf
 
QA Fest 2017. Ярослав Святкин. Тестовый фреймворк GEB для тестирования WEB пр...
QA Fest 2017. Ярослав Святкин. Тестовый фреймворк GEB для тестирования WEB пр...QA Fest 2017. Ярослав Святкин. Тестовый фреймворк GEB для тестирования WEB пр...
QA Fest 2017. Ярослав Святкин. Тестовый фреймворк GEB для тестирования WEB пр...
 
JavaCro'14 - Building interactive web applications with Vaadin – Peter Lehto
JavaCro'14 - Building interactive web applications with Vaadin – Peter LehtoJavaCro'14 - Building interactive web applications with Vaadin – Peter Lehto
JavaCro'14 - Building interactive web applications with Vaadin – Peter Lehto
 
From 0 to Spring Security 4.0
From 0 to Spring Security 4.0From 0 to Spring Security 4.0
From 0 to Spring Security 4.0
 
Vue JS @ MindDoc. The progressive road to online therapy
Vue JS @ MindDoc. The progressive road to online therapyVue JS @ MindDoc. The progressive road to online therapy
Vue JS @ MindDoc. The progressive road to online therapy
 
React native-firebase startup-mtup
React native-firebase startup-mtupReact native-firebase startup-mtup
React native-firebase startup-mtup
 
Google Web Toolkits
Google Web ToolkitsGoogle Web Toolkits
Google Web Toolkits
 
Webauthn Tutorial
Webauthn TutorialWebauthn Tutorial
Webauthn Tutorial
 
Creating a Facebook Clone - Part XXV - Transcript.pdf
Creating a Facebook Clone - Part XXV - Transcript.pdfCreating a Facebook Clone - Part XXV - Transcript.pdf
Creating a Facebook Clone - Part XXV - Transcript.pdf
 
Building the an End-to-End ASP.NET MVC 4, Entity Framework, HTML5, jQuery app...
Building the an End-to-End ASP.NET MVC 4, Entity Framework, HTML5, jQuery app...Building the an End-to-End ASP.NET MVC 4, Entity Framework, HTML5, jQuery app...
Building the an End-to-End ASP.NET MVC 4, Entity Framework, HTML5, jQuery app...
 
Building Persona: federated and privacy-sensitive identity for the Web (Open ...
Building Persona: federated and privacy-sensitive identity for the Web (Open ...Building Persona: federated and privacy-sensitive identity for the Web (Open ...
Building Persona: federated and privacy-sensitive identity for the Web (Open ...
 
Cutting edge HTML5 API you can use today (by Bohdan Rusinka)
 Cutting edge HTML5 API you can use today (by Bohdan Rusinka) Cutting edge HTML5 API you can use today (by Bohdan Rusinka)
Cutting edge HTML5 API you can use today (by Bohdan Rusinka)
 

Recently uploaded

UI5con 2024 - Bring Your Own Design System
UI5con 2024 - Bring Your Own Design SystemUI5con 2024 - Bring Your Own Design System
UI5con 2024 - Bring Your Own Design System
Peter Muessig
 
在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样
在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样
在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样
mz5nrf0n
 
如何办理(hull学位证书)英国赫尔大学毕业证硕士文凭原版一模一样
如何办理(hull学位证书)英国赫尔大学毕业证硕士文凭原版一模一样如何办理(hull学位证书)英国赫尔大学毕业证硕士文凭原版一模一样
如何办理(hull学位证书)英国赫尔大学毕业证硕士文凭原版一模一样
gapen1
 
Artificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension FunctionsArtificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension Functions
Octavian Nadolu
 
KuberTENes Birthday Bash Guadalajara - Introducción a Argo CD
KuberTENes Birthday Bash Guadalajara - Introducción a Argo CDKuberTENes Birthday Bash Guadalajara - Introducción a Argo CD
KuberTENes Birthday Bash Guadalajara - Introducción a Argo CD
rodomar2
 
14 th Edition of International conference on computer vision
14 th Edition of International conference on computer vision14 th Edition of International conference on computer vision
14 th Edition of International conference on computer vision
ShulagnaSarkar2
 
Fundamentals of Programming and Language Processors
Fundamentals of Programming and Language ProcessorsFundamentals of Programming and Language Processors
Fundamentals of Programming and Language Processors
Rakesh Kumar R
 
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
Bert Jan Schrijver
 
UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s EcosystemUI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
Peter Muessig
 
Enums On Steroids - let's look at sealed classes !
Enums On Steroids - let's look at sealed classes !Enums On Steroids - let's look at sealed classes !
Enums On Steroids - let's look at sealed classes !
Marcin Chrost
 
How Can Hiring A Mobile App Development Company Help Your Business Grow?
How Can Hiring A Mobile App Development Company Help Your Business Grow?How Can Hiring A Mobile App Development Company Help Your Business Grow?
How Can Hiring A Mobile App Development Company Help Your Business Grow?
ToXSL Technologies
 
zOS Mainframe JES2-JES3 JCL-JECL Differences
zOS Mainframe JES2-JES3 JCL-JECL DifferenceszOS Mainframe JES2-JES3 JCL-JECL Differences
zOS Mainframe JES2-JES3 JCL-JECL Differences
YousufSait3
 
Project Management: The Role of Project Dashboards.pdf
Project Management: The Role of Project Dashboards.pdfProject Management: The Role of Project Dashboards.pdf
Project Management: The Role of Project Dashboards.pdf
Karya Keeper
 
Malibou Pitch Deck For Its €3M Seed Round
Malibou Pitch Deck For Its €3M Seed RoundMalibou Pitch Deck For Its €3M Seed Round
Malibou Pitch Deck For Its €3M Seed Round
sjcobrien
 
UI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
UI5con 2024 - Boost Your Development Experience with UI5 Tooling ExtensionsUI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
UI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
Peter Muessig
 
Preparing Non - Technical Founders for Engaging a Tech Agency
Preparing Non - Technical Founders for Engaging  a  Tech AgencyPreparing Non - Technical Founders for Engaging  a  Tech Agency
Preparing Non - Technical Founders for Engaging a Tech Agency
ISH Technologies
 
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
dakas1
 
How to write a program in any programming language
How to write a program in any programming languageHow to write a program in any programming language
How to write a program in any programming language
Rakesh Kumar R
 
Top Benefits of Using Salesforce Healthcare CRM for Patient Management.pdf
Top Benefits of Using Salesforce Healthcare CRM for Patient Management.pdfTop Benefits of Using Salesforce Healthcare CRM for Patient Management.pdf
Top Benefits of Using Salesforce Healthcare CRM for Patient Management.pdf
VALiNTRY360
 
The Key to Digital Success_ A Comprehensive Guide to Continuous Testing Integ...
The Key to Digital Success_ A Comprehensive Guide to Continuous Testing Integ...The Key to Digital Success_ A Comprehensive Guide to Continuous Testing Integ...
The Key to Digital Success_ A Comprehensive Guide to Continuous Testing Integ...
kalichargn70th171
 

Recently uploaded (20)

UI5con 2024 - Bring Your Own Design System
UI5con 2024 - Bring Your Own Design SystemUI5con 2024 - Bring Your Own Design System
UI5con 2024 - Bring Your Own Design System
 
在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样
在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样
在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样
 
如何办理(hull学位证书)英国赫尔大学毕业证硕士文凭原版一模一样
如何办理(hull学位证书)英国赫尔大学毕业证硕士文凭原版一模一样如何办理(hull学位证书)英国赫尔大学毕业证硕士文凭原版一模一样
如何办理(hull学位证书)英国赫尔大学毕业证硕士文凭原版一模一样
 
Artificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension FunctionsArtificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension Functions
 
KuberTENes Birthday Bash Guadalajara - Introducción a Argo CD
KuberTENes Birthday Bash Guadalajara - Introducción a Argo CDKuberTENes Birthday Bash Guadalajara - Introducción a Argo CD
KuberTENes Birthday Bash Guadalajara - Introducción a Argo CD
 
14 th Edition of International conference on computer vision
14 th Edition of International conference on computer vision14 th Edition of International conference on computer vision
14 th Edition of International conference on computer vision
 
Fundamentals of Programming and Language Processors
Fundamentals of Programming and Language ProcessorsFundamentals of Programming and Language Processors
Fundamentals of Programming and Language Processors
 
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
 
UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s EcosystemUI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
 
Enums On Steroids - let's look at sealed classes !
Enums On Steroids - let's look at sealed classes !Enums On Steroids - let's look at sealed classes !
Enums On Steroids - let's look at sealed classes !
 
How Can Hiring A Mobile App Development Company Help Your Business Grow?
How Can Hiring A Mobile App Development Company Help Your Business Grow?How Can Hiring A Mobile App Development Company Help Your Business Grow?
How Can Hiring A Mobile App Development Company Help Your Business Grow?
 
zOS Mainframe JES2-JES3 JCL-JECL Differences
zOS Mainframe JES2-JES3 JCL-JECL DifferenceszOS Mainframe JES2-JES3 JCL-JECL Differences
zOS Mainframe JES2-JES3 JCL-JECL Differences
 
Project Management: The Role of Project Dashboards.pdf
Project Management: The Role of Project Dashboards.pdfProject Management: The Role of Project Dashboards.pdf
Project Management: The Role of Project Dashboards.pdf
 
Malibou Pitch Deck For Its €3M Seed Round
Malibou Pitch Deck For Its €3M Seed RoundMalibou Pitch Deck For Its €3M Seed Round
Malibou Pitch Deck For Its €3M Seed Round
 
UI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
UI5con 2024 - Boost Your Development Experience with UI5 Tooling ExtensionsUI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
UI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
 
Preparing Non - Technical Founders for Engaging a Tech Agency
Preparing Non - Technical Founders for Engaging  a  Tech AgencyPreparing Non - Technical Founders for Engaging  a  Tech Agency
Preparing Non - Technical Founders for Engaging a Tech Agency
 
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
 
How to write a program in any programming language
How to write a program in any programming languageHow to write a program in any programming language
How to write a program in any programming language
 
Top Benefits of Using Salesforce Healthcare CRM for Patient Management.pdf
Top Benefits of Using Salesforce Healthcare CRM for Patient Management.pdfTop Benefits of Using Salesforce Healthcare CRM for Patient Management.pdf
Top Benefits of Using Salesforce Healthcare CRM for Patient Management.pdf
 
The Key to Digital Success_ A Comprehensive Guide to Continuous Testing Integ...
The Key to Digital Success_ A Comprehensive Guide to Continuous Testing Integ...The Key to Digital Success_ A Comprehensive Guide to Continuous Testing Integ...
The Key to Digital Success_ A Comprehensive Guide to Continuous Testing Integ...
 

InheritedWidget is your friend - GDG London (2018-08-08)

  • 1. InheritedWidget is your friend Andrea Bizzotto codingwithflutter.com @biz84 GDG London 08-08-2018
  • 2. Get access to stuff Networking Authentication Database Secure Storage FileSystem
  • 3. Get access to stuff 🌍 Global Access 🌗 Dependency Injection 🌝 Scoped Access
  • 5. Get access to stuff 🌍 Global Access 🌗 Dependency Injection 🌝 Scoped Access
  • 6. import 'package:firebase_auth/firebase_auth.dart'; class LoginPage extends StatelessWidget { LoginPage({this.onSignedIn}); final VoidCallback onSignedIn; void signInUser(String email, String password) async { try { await FirebaseAuth.instance.signInWithEmailAndPassword( email: email, password: password); onSignedIn(); } catch (e) { // Sign in failed: show error to user } } } Global Access
  • 7. import 'package:firebase_auth/firebase_auth.dart'; class LoginPage extends StatelessWidget { LoginPage({this.onSignedIn}); final VoidCallback onSignedIn; void signInUser(String email, String password) async { try { await FirebaseAuth.instance.signInWithEmailAndPassword( email: email, password: password); onSignedIn(); } catch (e) { // Sign in failed: show error to user } } } Global Access
  • 8. import 'package:firebase_auth/firebase_auth.dart'; class LoginPage extends StatelessWidget { LoginPage({this.onSignedIn}); final VoidCallback onSignedIn; void signInUser(String email, String password) async { try { await FirebaseAuth.instance.signInWithEmailAndPassword( email: email, password: password); onSignedIn(); } catch (e) { // Sign in failed: show error to user } } } Global Access
  • 9. import 'package:firebase_auth/firebase_auth.dart'; class LoginPage extends StatelessWidget { LoginPage({this.onSignedIn}); final VoidCallback onSignedIn; void signInUser(String email, String password) async { try { await FirebaseAuth.instance.signInWithEmailAndPassword( email: email, password: password); onSignedIn(); } catch (e) { // Sign in failed: show error to user } } } Global Access
  • 10. import 'package:firebase_auth/firebase_auth.dart'; class LoginPage extends StatelessWidget { LoginPage({this.onSignedIn}); final VoidCallback onSignedIn; void signInUser(String email, String password) async { try { await FirebaseAuth.instance.signInWithEmailAndPassword( email: email, password: password); onSignedIn(); } catch (e) { // Sign in failed: show error to user } } } Global Access
  • 11. Global Access 😀 Very little code 🙁 Tight Coupling 🙁 Hard to test 😱 Singletons everywhere
  • 15. Access 🌍 Global Access 🌗 Dependency Injection 🌝 Scoped Access
  • 18. import ‘package:login_demo/auth.dart’; class LoginPage extends StatelessWidget { LoginPage({this.auth, this.onSignedIn}); final Auth auth; final VoidCallback onSignedIn; void signInUser(String email, String password) async { try { await auth.signInWithEmailAndPassword( email: email, password: password); onSignedIn(); } catch (e) { // Sign in failed: show error to user } } } Dependency Injection
  • 19. import ‘package:login_demo/auth.dart’; class LoginPage extends StatelessWidget { LoginPage({this.auth, this.onSignedIn}); final Auth auth; final VoidCallback onSignedIn; void signInUser(String email, String password) async { try { await auth.signInWithEmailAndPassword( email: email, password: password); onSignedIn(); } catch (e) { // Sign in failed: show error to user } } } Dependency Injection
  • 21. Dependency Injection 🙃 A bit more boilerplate 🙂 Tell, don’t ask 🎉 Easy to test Photo by Adam Whitlock on Unsplash
  • 22. 🙃 A bit more boilerplate 🙂 Tell, don’t ask 🎉 Easy to test 😒 Plumbing Dependency Injection
  • 23. A third way? 🌍 Global access 🌗 Dependency injection 🌝 Scoped access
  • 27. import 'package:login_demo/auth_provider.dart'; class LoginPage extends StatelessWidget { LoginPage({this.onSignedIn}); final VoidCallback onSignedIn; void signInUser(String email, String password) async { try { final auth = AuthProvider.of(context).auth; await auth.signInWithEmailAndPassword( email: email, password: password); onSignedIn(); } catch (e) { // Sign in failed: show error to user } } } InheritedWidget
  • 28. import 'package:login_demo/auth_provider.dart'; class LoginPage extends StatelessWidget { LoginPage({this.onSignedIn}); final VoidCallback onSignedIn; void signInUser(String email, String password) async { try { final auth = AuthProvider.of(context).auth; await auth.signInWithEmailAndPassword( email: email, password: password); onSignedIn(); } catch (e) { // Sign in failed: show error to user } } } InheritedWidget
  • 30. class AuthProvider extends InheritedWidget { AuthProvider({Key key, Widget child, this.auth}) : super(key: key, child: child); final Auth auth; @override bool updateShouldNotify(InheritedWidget oldWidget) => true; static AuthProvider of(BuildContext context) { return context.inheritFromWidgetOfExactType(AuthProvider); } } InheritedWidget
  • 31. class AuthProvider extends InheritedWidget { AuthProvider({Key key, Widget child, this.auth}) : super(key: key, child: child); final Auth auth; @override bool updateShouldNotify(InheritedWidget oldWidget) => true; static AuthProvider of(BuildContext context) { return context.inheritFromWidgetOfExactType(AuthProvider); } } InheritedWidget
  • 32. class AuthProvider extends InheritedWidget { AuthProvider({Key key, Widget child, this.auth}) : super(key: key, child: child); final Auth auth; @override bool updateShouldNotify(InheritedWidget oldWidget) => true; static AuthProvider of(BuildContext context) { return context.inheritFromWidgetOfExactType(AuthProvider); } } InheritedWidget
  • 33. class AuthProvider extends InheritedWidget { AuthProvider({Key key, Widget child, this.auth}) : super(key: key, child: child); final Auth auth; @override bool updateShouldNotify(InheritedWidget oldWidget) => true; static AuthProvider of(BuildContext context) { return context.inheritFromWidgetOfExactType(AuthProvider); } } InheritedWidget
  • 34. class AuthProvider extends InheritedWidget { AuthProvider({Key key, Widget child, this.auth}) : super(key: key, child: child); final Auth auth; @override bool updateShouldNotify(InheritedWidget oldWidget) => true; static AuthProvider of(BuildContext context) { return context.inheritFromWidgetOfExactType(AuthProvider); } } InheritedWidget
  • 35. class AuthProvider extends InheritedWidget { AuthProvider({Key key, Widget child, this.auth}) : super(key: key, child: child); final Auth auth; @override bool updateShouldNotify(InheritedWidget oldWidget) => true; static AuthProvider of(BuildContext context) { return context.inheritFromWidgetOfExactType(AuthProvider); } } InheritedWidget
  • 36. class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return AuthProvider( auth: Auth(), child: MaterialApp( title: 'Flutter login demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: RootPage(), ), ); } } InheritedWidget
  • 37. InheritedWidget 😐 Some boilerplate code 😀 Easy to test 😀 Easy to maintain 🧐 Tradeoffs
  • 39. • Class.of(context) shouldn’t be called from initState() • Use didChangeDependencies() instead. • ⚠ called more than once! InheritedWidget
 tradeoffs? StatefulWidget
  • 40. abstract class Database { Future<void> addTweet(Tweet tweet); Stream<List<Tweet>> tweetsStream(); } class AppDatabase implements Database { AppDatabase({this.userId}); final String userId; Future<void> addTweet(Tweet tweet) { ... } Stream<List<Tweet>> tweetsStream() { ... } } Twitter Client users/$userId/tweets
  • 41. abstract class Database { Future<void> addTweet(Tweet tweet); Stream<List<Tweet>> tweetsStream(); } class AppDatabase implements Database { AppDatabase({this.userId}); final String userId; Future<void> addTweet(Tweet tweet) { ... } Stream<List<Tweet>> tweetsStream() { ... } } Twitter Client users/$userId/tweets
  • 42. abstract class Database { Future<void> addTweet(Tweet tweet); Stream<List<Tweet>> tweetsStream(); } class AppDatabase implements Database { AppDatabase({this.userId}); final String userId; Future<void> addTweet(Tweet tweet) { ... } Stream<List<Tweet>> tweetsStream() { ... } } Twitter Client users/$userId/tweets
  • 43. abstract class Database { String userId; Future<void> addTweet(Tweet tweet); Stream<List<Tweet>> tweetsStream(); } class AppDatabase implements Database { Future<void> addTweet(Tweet tweet) { ... } Stream<List<Tweet>> tweetsStream() { ... } } class ServiceProvider implements InheritedWidget { ServiceProvider({Widget child, this.auth, this.database}); final BaseAuth auth; final Database database; } Twitter Client users/$userId/tweets
  • 44. abstract class Database { String userId; Future<void> addTweet(Tweet tweet); Stream<List<Tweet>> tweetsStream(); } class AppDatabase implements Database { Future<void> addTweet(Tweet tweet) { assert(userId != null); } Stream<List<Tweet>> tweetsStream() { assert(userId != null); } } class ServiceProvider implements InheritedWidget { ServiceProvider({Widget child, this.auth, this.database}); final BaseAuth auth; final Database database; } Twitter Client users/$userId/tweets
  • 45. abstract class Database { Future<void> addTweet(Tweet tweet); Stream<List<Tweet>> tweetsStream(); } class AppDatabase implements Database { AppDatabase({this.userId}); final String userId; Future<void> addTweet(Tweet tweet) { ... } Stream<List<Tweet>> tweetsStream() { ... } } class DatabaseProvider implements InheritedWidget { DatabaseProvider({Widget child, this.database}); final Database database; } Twitter Client users/$userId/tweets
  • 46. class Provider<T> extends InheritedWidget InheritedWidget
 multiple providers? 💡 • AuthProvider • DatabaseProvider • …
  • 47. class Provider<T> extends InheritedWidget { Provider({Key key, Widget child, this.object}) : super(key: key, child: child); final T object; @override bool updateShouldNotify(InheritedWidget oldWidget) => true; static T of<T>(BuildContext context) { final type = _typeOf<Provider<T>>(); Provider<T> provider = context .inheritFromWidgetOfExactType(type); return provider.object; } static Type _typeOf<T>() => T; } InheritedWidget
  • 49. Get access to stuff 🌍 Global Access 🌗 Dependency Injection 🌝 Scoped Access
  • 50. Get access to stuff Code required Testing Maintainability Global
 Access 😀 😭 😭 Dependency
 Injection 🙂 😀 🙁 Scoped
 Access 😐 😀 😀 *Your mileage may vary
  • 51. Get access to stuff 🌍 Global Access 🌗 Dependency Injection 🌝 Scoped Access 🤓 Service Locator
  • 53. THANK YOU codingwithflutter.com @biz84 Login Demo [GitHub] Widget — State — BuildContext — InheritedWidget