Flutter redux thunk action parameters - redux

I am trying to use redux_thunk but what I really don't understand from the demo is how to send parameters to that function. I have a file actions.dart where are
have all the actions. From my component I want to dispatch to that action some parameters so that I make a request to API. For example I want to login with username, password without saving them in state
actions.dart
final ThunkAction<AppState> login = (Store<AppState> store) async {
await new Future.delayed(
new Duration(seconds: 3),
() => "Waiting complete",
);
store.dispatch(OtherAction(....));
};
component.dart
class LoginBtn extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StoreConnector<AppState, Function>(
converter: (store) => (){
login(store);
},
builder: (context, callback) {
return RaisedButton(
highlightElevation: 20.0,
child: Text('Login', style: TextStyle(color: Colors.white)),
color: Color(0xFF0f7186),
onPressed: () {
callback();
});
});
}
}
Can someone help me with some quick fix or demo. Thanks!
Something like this?
class MyAction {
String gender;
MyAction(
{this.gender});
ThunkAction<AppState> getDate() {
return (Store<AppState> store) async {...};
}
}

I think the easiest way to do it is using a function for creating the action:
ThunkAction<String> waitAndDispatch(int secondsToWait) {
return (Store<String> store) async {
final searchResults = await new Future.delayed(
new Duration(seconds: secondsToWait),
() => "Search Results",
);
store.dispatch(searchResults);
};
}
then, dispatch it like:
store.dispatch(waitAndDispatch(3));

There are two ways to go about doing this. Two of them wrap the action you're about to dispatch in a class like what you did above.
class MyAction {
String gender;
String name;
MyAction(this.gender, this.name);
void getDate<AppState>(Store<AppState> store) {
print("store is $store, gender is $gender, name is $name");
}
}
1. Create another middleware or modify the current one. Call the getDate() from
within the middleware.
Eg.
// this middleware intercepts any MyAction
void myMiddleware<AppState>(
Store<AppState> store,
dynamic action,
NextDispatcher next
) {
if (action is MyAction) {
action.getDate(store);
} else {
next(action);
}
}
Then we dispatch as such:
store.dispatch(new MyAction("m", "Peterson")) ;
2. Instead of modifying or creating another middleware, we make getDate() a
ThunkAction and call the getDate() before dispatching. Eg.
class MyAction {
String gender;
String name;
MyAction(this.gender, this.name);
ThunkAction<AppState> getDate = (Store<AppState> store) {
print("store is $store, gender is $gender, name is $name");
}
}
Then we dispatch it like so:
store.dispatch(new MyAction(...).getDate)
The second approach, which is the approach you used in the above example is how I would go about doing it because i dont have to meddle with the middleware.

For this functionality you should extend CallableThunkAction<State> based on official docs:
An interface that can be implemented by end-users to create a class-based [ThunkAction].
Sample
class SigninAction extends CallableThunkAction<AuthState> {
SigninAction(this.mobile);
final String mobile;
#override
call(Store<AuthState> store) async {
// call to server endpoint
store.dispatch(results);
}
}
then, dispatch it like:
store.dispatch(SigninAction('mobile number'));

Related

Flutter programmatically building a referral system with deep link

I need to implement a deep link or referral system with my flutter application. The theory is
Singup and Signin will be handled by custom backend and not firebase
After a user signs up to my application he will be able to refer the app to others and if others install the app the referrer will gain some points.
Most work in this process will be handled by our custom backend. What I need is when someone uses my referral code I want that code during his/her signup.
So this is the service layer I created:
class DynamicLinkService {
final dynamicLink = FirebaseDynamicLinks.instance;
handleDynamicLink() async {
await dynamicLink.getInitialLink();
// dynamicLink.onLink(onSuccess: (PendingDynamicLinkData data) async {
// // something
// },
// onError: (OnLinkErrorException e) async {
// // something
// },
// );
}
Future<String> createDynamicLink() async {
User user = Store.instance.getUser();
String userId = user.id;
print("User id = $userId");
final DynamicLinkParameters dynamicLinkParameters = DynamicLinkParameters(
uriPrefix: 'https://shoppydev.page.link',
link: Uri.parse(
'https://shoppydev.page.link/?invitedBy=$userId',
),
androidParameters: AndroidParameters(
packageName: 'co.company.app',
minimumVersion: 0,
),
iosParameters: IOSParameters(
bundleId: 'co.company.app',
minimumVersion: '0.0.1',
),
socialMetaTagParameters: SocialMetaTagParameters(
title: 'Refer A friend',
description: 'Refer and earn points',
),
);
final ShortDynamicLink shortDynamicLink = await dynamicLink.buildShortLink(
dynamicLinkParameters,
);
final Uri dynamicUrl = shortDynamicLink.shortUrl;
print(dynamicUrl.toString());
return dynamicUrl.toString();
}
void handleSuccessfulLinking(PendingDynamicLinkData? data) async {
final Uri? deepLink = data!.link;
print(deepLink.toString());
if (deepLink != null) {
var isRefer = deepLink.toString().contains('invitedBy');
if (isRefer) {
var code = deepLink.toString().split('invitedBy=')[1];
print(code);
if (code != null) {
// code contains the referrer's user id
// signup with the referrer's id
}
}
}
}
}
As you can see I tried to create a unique referral link with the user id for now. But most guides I am following as well as some github repos did something like this for handling dynamic link:
dynamicLink.onLink(onSuccess: (PendingDynamicLinkData data) async {
// something
},
onError: (OnLinkErrorException e) async {
// something
},
);
Which throws: The expression doesn't evaluate to a function, so it can't be invoked.
Other notes that might help:
Inside my app.dart I have:
class App extends StatefulWidget {
const App({Key? key}) : super(key: key);
#override
State<App> createState() => _AppState();
}
class _AppState extends State<App> {
#override
void initState() {
super.initState();
initDynamicLinks(context);
}
#override
Widget build(BuildContext context) {
final provider = Provider.of<LocaleProvider>(context);
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'App Name',
theme: ThemeData(
primarySwatch: Colors.blue,
),
onGenerateRoute: buildRouter,
locale: provider.locale,
supportedLocales: L10n.all,
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
);
}
/*
Dynamic Links
*/
void initDynamicLinks(BuildContext context) async {
final PendingDynamicLinkData? data =
await FirebaseDynamicLinks.instance.getInitialLink();
final Uri? link = data?.link;
if (link != null) {
Navigator.pushNamed(context, link.path);
}
}
}
Issues I have faced till now:
I still haven't found a solid documentation on how to get the referral code(which is need for rewarding the referrer).
I have already checked out this two posts on stack:
Implementing referral rewards in Flutter
Flutter - How to pass custom arguments in firebase dynamic links for app invite feature?
In short, I want to create a unique refer link with my user id. Share the user id with someone else and when he/she registers to my app I want to get the referral code attached to the link.
Example: https://app.page.link/?invitedBy=$userId
When someone installs and registers I want the userId so I can pass it to the invitedBy property of SignUpRequest.
Edit: I think I didn't clarify my question enough. So I will set it up with an example:
I want an unique referral link on my phone which I can give to my friend John. And once he downloads and registers the app I want to get some reward points.
So when he sends his SignUpRequest to the Backend I want my referral code to go with that request, so the request will look like:
SignUpRequest()
..name = "John Doe",
..email = "john#gmail.com"
..invitedBy = "...my referral code goes here"
All the other validation and point giving process will be done in the BE
Put all of the below code in the App.dart or Splash screen, basically the first screen
initState
#override
void initState() {
super.initState();
_initDynamicLinks();
}
_initDynamicLinks - this is from where the dynamic link will be launched
Future<void> _initDynamicLinks() async {
final PendingDynamicLinkData data = await instance.getInitialLink();
final Uri deepLink = data?.link;
_handleDynamicLink(deepLink);
FirebaseDynamicLinks.instance.onLink.listen((dynamicLink) {
final uri = dynamicLink.link;
_handleDynamicLink(uri);
}).onError((e) {
print('onLinkError');
print(e.message);
});
}
_handleDynamicLink - this is where you handle the link and parse it
void _handleDynamicLink(Uri deepLink) async {
if (deepLink != null) {
final url = deepLink.toString();
var isRefer = url.contains('invitedBy');
if (isRefer) {
var code = url.split('invitedBy=')[1];
print(code);
if (code != null) {
// code contains the referrer's user id
// signup with the referrer's id
}
}
}
}
I think this way will be more clean
first add this widget
class DynamicLinksWidgetHandler extends StatefulWidget {
const DynamicLinksWidgetHandler({
super.key,
required this.child,
});
final Widget child;
#override
State<DynamicLinksWidgetHandler> createState() =>
_DynamicLinksWidgetHandlerState();
}
class _DynamicLinksWidgetHandlerState extends State<DynamicLinksWidgetHandler> {
#override
void initState() {
super.initState();
_initDynamicLinks();
}
// _initDynamicLinks - this is from where the dynamic link will be launched
Future<void> _initDynamicLinks() async {
final data = await FirebaseDynamicLinks.instance.getInitialLink();
final Uri? deepLink = data?.link;
_handleDynamicLink(deepLink);
FirebaseDynamicLinks.instance.onLink.listen((dynamicLink) {
final uri = dynamicLink.link;
_handleDynamicLink(uri);
}).onError((e) {
print('onLinkError');
print(e.message);
});
}
// _handleDynamicLink - this is where you handle the link and parse it
void _handleDynamicLink(Uri? deepLink) async {
log('_handleDynamicLink:$deepLink');
final code = deepLink?.queryParameters['invitedby'];
if (code == null) return;
// save code to backend
log(code);
}
#override
Widget build(BuildContext context) {
return widget.child;
}
}
and then wrap it on your app widget like this
runApp(
const DynamicLinksWidgetHandler(
child: MyApp(),
),
);

Handling different scenarios for app redirection using Firebase Dynamic Links

I am trying to create a streaming app.
I am integrating Firebase Dynamic links, so hosts can share a link to join their session.
But I am kinda lost on how to implement it, and I would like to know your insights about this.
So let me start with the structure, this is the main pages:
MainApp
Authenticate
LoginPage
HomePage
Profile
JoinPage
This is how I setup my app, they are all wrap to Authenticate widget, this widget determines if user should be redirected to login or the home page. Pretty simple eh. :)
Then here comes the Dynamic links.
My dynamic links has a query params on it to determine which session to join. It looks like this:
https://my.app.link/join-session?sessionId=\<some random keys>
And this is what I want to handle it.
If (user is not logged in ) {
// save the sessionId to a singleton (or somewhere that persists along the app lifecycle, I use Provider here)
// redirects user to login page
// user logged in
// upon going to home page, will retrieve the saved sessionId and redirect user to the session using the sessionId
} else {
// retrieve sessionId
// redirect user to the session using the sessionId
}
This is how my code looks:
MainApp.dart logic
....
if (state == PageLoadState.DONE) {
return MultiProvider(
providers: [
Provider<SampleAppAuthProvider>(
create: (_) => SampleAppAuthProvider(FirebaseAuth.instance),
),
Provider<SampleAppConfigProvider>(
create: (_) => SampleAppConfigProvider(sharedPrefs)
),
StreamProvider(
initialData: null,
create: (context) => context.read<SampleAppAuthProvider>().authState,
),
Provider<DynamicLinkService>(create: (_) => DynamicLinkService(instance: FirebaseDynamicLinks.instance)),
ChangeNotifierProvider(create: (_) => UsersApi(repo: Repository('users')), lazy: true),
ChangeNotifierProvider(create: (_) => SessionsApi(repo: Repository('sessions')), lazy: true),
ChangeNotifierProvider(create: (_) => MessagesApi(repo: Repository('messages')), lazy: true),
],
child: MaterialApp(
title: 'SampleApp!',
theme: defaultTheme(),
localizationsDelegates: context.localizationDelegates,
supportedLocales: context.supportedLocales,
locale: context.locale,
onGenerateRoute: router.generateRoute,
home: Authenticate(),
),
);
}
......
And this is my Authenticate Page:
class Authenticate extends StatelessWidget {
#override
Widget build(BuildContext context) {
context.read<DynamicLinkService>().handleDynamicLinks();
final firebaseUser = context.read<User>();
if (firebaseUser != null) {
return HomePage();
}
return LoginPage();
}
}
I have also create a separate service for handling the dynamic links:
DynamicLinkService.dart
class DynamicLinkService {
DynamicLinkService({#required this.instance});
final FirebaseDynamicLinks instance;
String _sessionIdToJoin = '';
get sessionIdToJoin => _sessionIdToJoin;
void clearSessionId () => _sessionIdToJoin = '';
Future handleDynamicLinks() async {
final PendingDynamicLinkData data =
await instance.getInitialLink();
_handleDeepLink(data);
instance.onLink(
onSuccess: (PendingDynamicLinkData dynamicLink) async {
_handleDeepLink(dynamicLink);
}, onError: (OnLinkErrorException e) async {
print('Link Failed: ${e.message}');
});
}
void _handleDeepLink(PendingDynamicLinkData data) {
final Uri deepLink = data?.link;
if (deepLink != null) {
print('_handleDeepLink | deeplink: $deepLink');
bool isJoiningSession = deepLink.pathSegments.contains('session');
if(isJoiningSession) {
String sessionId = deepLink.queryParameters['sessionId'];
if (sessionId != null) {
_sessionIdToJoin = sessionId;
}
}
}
}
}
I also have another UtilService that generates dynamic links:
Utils.dart
class Utils {
....
static Future<String> generateLink(String sessionId) async {
final DynamicLinkParameters parameters = DynamicLinkParameters(
uriPrefix: AppConfig.dynamicLinkBaseUrl,
link: Uri.parse('${AppConfig.dynamicLinkBaseUrl}/join-session?sessionId=$sessionId'),
dynamicLinkParametersOptions: DynamicLinkParametersOptions(
shortDynamicLinkPathLength: ShortDynamicLinkPathLength.unguessable
),
androidParameters: AndroidParameters(
packageName: 'com.sample.app',
minimumVersion: 0,
),
);
final Uri dynamicUrl = await parameters.buildUrl();
final ShortDynamicLink shortenedLink =
await DynamicLinkParameters.shortenUrl(
dynamicUrl,
DynamicLinkParametersOptions(
shortDynamicLinkPathLength: ShortDynamicLinkPathLength.unguessable),
);
final Uri shortUrl = shortenedLink.shortUrl;
return AppConfig.dynamicLinkBaseUrl + shortUrl.path;
}
...
}
On my home page I have this method that will should be called whenever user lands in the homepage:
HomePage.dart:
class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
....
_navigateToDestination() {
DynamicLinkService _service = context.select((DynamicLinkService service) => service);
String sessionToJoin = _service.sessionIdToJoin;
User user = context.read<User>();
if(sessionToJoin != '') {
_service.clearSessionId();
Navigator.pushNamed(context,
AppRoutes.joinStream,
arguments: StreamLiveArguments(
channelName: sessionToJoin,
user: AppUtil.getName(user),
role: ClientRole.Audience
)
);
}
}
#override
initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
_navigateToDestination();
});
}
#override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
#override
void didChangeAppLifecycleState(final AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
_navigateToDestination();
}
}
....
}
The issue on this implementation is that sometimes it works and sometimes it does not work and I am not sure why. :(
Should I just use a simple class instead of a provider? If yes, how can I persists the sessionId?
Other Scenarios that I want to handle is when user is in different page like the Profile Page.
At this point, user can minimize the app and can click the dynamic link from other sites or from messenger.
When the app resumes, it will open in the ProfilePage where it doesn't have handling for dynamic links (only HomePage and LoginPage has handling on it). How can I remedy this? Should I add handling of dynamic links to all my pages? Or perhaps can I create a dynamic link that can redirect to a certain page in my app? If yes, how can I do that?
I am kinda new in implementing the dynamic links (as well as Providers) and would like your opinion on this issue.Thanks in advance and I hope someone can help me or give me some insights on best practices on how to do this.

How do I print a list from a Firebase Database query using Flutter?

I'm trying to print a list of attributes from my firebase database. The database is currently structured like this:
I would first like to print a list of show names to the console so I can see that it works and then add it to a ListView later. Any help is appreciated!
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
// This is the model class
class Mod {
final String name;
final String nextEpisode;
final String prevEpisode;
Mod(this.name, this.nextEpisode, this.prevEpisode);
Mod.fromJson(Map<String, dynamic> json)
: name = json['name'],
nextEpisode = json['nextEpisode'],
prevEpisode = json['prevEpisode'];
}
// This is the screen class
class FTest2 extends StatefulWidget {
#override
_FTest2State createState() => _FTest2State();
}
class _FTest2State extends State<FTest2> {
List<Mod> list = List();
MakeCall() {
final mainReference = FirebaseDatabase.instance.reference();
mainReference.child('-M5Uol7Xldnc8wvNXnNg').once().then((DataSnapshot dataSnapshot){
this.setState(() {
for(var value in dataSnapshot.value){
list.add(Mod.fromJson(value));
}
});
});
print(list);
}
void getData() {
MakeCall();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('This is App Bar for the FB Test')),
body: Column(
children: <Widget>[
RaisedButton(
child: Text('Press for data'),
onPressed: () {
getData();
},
),
],
));
}
}
You're looping over the nodes of one specific show, which means that your value is actually one of the child properties under that: name, nextEpisode, prevEpisode. What you're probably looking for is to listen to onChildAdded for all shows, and then get the name property for each:
mainReference.child('shows')
.onChildAdded
.forEach((event) => {
print(event.snapshot.key+": "+event.snapshot.value.toString());
this.setState(() {
list.add(Mod.fromJson(event.snapshot.value["name"]));
});
});
Also see my answer form a few weeks ago here: Flutter: Firebase Real-Time database orderByChild has no impact on query result
Your reference is wrong, you need to traverse the database from top to the node you want to retrieve, therefore use the following:
final mainReference = FirebaseDatabase.instance.reference("shows");
mainReference.child('-M5Uol7Xldnc8wvNXnNg').once().then((DataSnapshot dataSnapshot){
pass the argument shows to the reference() method.

How to finish the async Future task before executing the next instruction Flutter

I make a function call to my database, which updates a local object after getting data and takes a few moments.
Because of the Async task, the program moves to the next line of code. unfortunately I need the local object that gets updated with the async call for the next line of code.
how can I wait for my async task to finish before the next piece of code is executed? thank you
edit: adding code to explain
updateUser() {
return FutureBuilder(
future: updateUserData(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return Text("hello not");
} else {
return Text('Hello!');
}
},
);}
#override
Widget build(BuildContext context) {
switch (_authStatus) {
case AuthStatus.notSignedIn:
return new LoginPage(
auth: auth,
CurrentUser: CurrentUser,
onSignedIn: _signedIn,
);
case AuthStatus.signedIn:
{
updateUser(); //THIS TAKES A COUPLE SECONDS TO FINISH BUT I NEED TO SEND IT TO THE NEXT PAGE
return new HomePage(
auth: auth,
CurrentUser: CurrentUser,
onSignedOut: _signedOut,
);
}
}
}
}
You can use await keyword in async function.
eg:
void someFunc() async {
await someFutureFunction();
// Your block of code
}
Here your block of code wont run until someFutureFunction returns something.
You can also use with custom async function like below example:
(() async {
await restApis.getSearchedProducts(widget.sub_cats_id,widget.keyword).then((val) => setState(()
{
setState(() {
data = val["data"];
});
}));
})();
This might help, The below sample code has two functions,
Below function is used to load the assets and return the JSON content.
Future<String> _loadCountriesAsset() async {
return await rootBundle.loadString('assets/country_codes.json');
}
the other function will use the JSON content and convert the format to model and return to the class.
Future<List<CountryCode>> loadCountryCodes() async {
String jsonString = await _loadCountriesAsset();
final jsonResponse = json.decode(jsonString);
// print(jsonResponse);
CountriesCodeList countriesCodeList =
new CountriesCodeList.fromJson(jsonResponse);
// print("length " + countriesCodeList.codes.length.toString());
return countriesCodeList.codes;
}
Usage in the class, defined a method to call the loadCountryCodes() function from services.dart file.
Future getCountryCodes() async {
var countryCodesList = await loadCountryCodes();
print("**** length " + countryCodesList.length.toString());
// Perform the operations, or update to the UI or server. It should be same for API call as well.
}
Hope this helps.

Flutter Redux Navigator GlobalKey.currentState returns null

I am developing Flutter with Redux.
When a user starts an application, I want Redux to automatically dispatch an action. This action will make the Navigator push different routes dependently.
This snippet provided by a Flutter dev member uses the GlobalKey to use the Navigator inside the middleware.
Following this, I organize my code as follows:
main.dart
void main() {
final store = new Store(appStateReducer,
middleware:createRouteMiddleware()
);
runApp(new MyApp(store));
}
class MyApp extends StatelessWidget {
final Store<AppState> store;
MyApp(this.store);
#override
Widget build(BuildContext context) {
return new StoreProvider<AppState>(
store: store,
child: MaterialApp(
routes: {
Routes.REGISTER: (context) {
return RegisterScreenContainer();
},
Routes.SET_PROFILE: (context) {
return SetProfileScreenContainer();
},
//Routes.HOME = "/" so this route will be run first
Routes.HOME: (context) {
return StoreBuilder<AppState>(
//onInit is called to dispatch an action automatically when the application starts. The middleware will catch this and navigate to the appropriate route.
onInit: (store) => store.dispatch(
ChangeRoute(routeStateType: RouteStateType.Register)),
builder: (BuildContext context, Store vm) {
return RegisterScreenContainer();
},
);
},
}));
}
}
middleware.dart
Middleware<AppState> createRouteMiddleware(
{#required GlobalKey<NavigatorState> navigatorKey}) {
final changeRoute = _createChangeRouteMiddleware(navigatorKey: navigatorKey);
return TypedMiddleware<AppState, ChangeRoute>(changeRoute);
}
Middleware<AppState> _createChangeRouteMiddleware(
{#required GlobalKey<NavigatorState> navigatorKey}) {
print(navigatorKey.currentState);
return (Store store, action, NextDispatcher next) async {
switch ((action.routeStateType as RouteStateType)) {
case RouteStateType.Home:
navigatorKey.currentState.pushNamed(Routes.HOME);
break;
case RouteStateType.Register:
//The middleware intercepts and push the appropriate route depending on the action
navigatorKey.currentState.pushNamed(Routes.REGISTER);
break;
default:
break;
}
next(action);
};
}
And this is the error I got
[ERROR:topaz/lib/tonic/logging/dart_error.cc(16)] Unhandled exception:
E/flutter ( 2544): NoSuchMethodError: The method 'pushNamed' was called on null.
E/flutter ( 2544): Receiver: null
E/flutter ( 2544): Tried calling: pushNamed("/register")
This means that the action was successfully dispatched, however, the currentState of the navigatorKey was null.
What am I missing here?
Note that I am aware of this seemingly similar question which does not really apply to my question. Even when I merge the main.dart and middleware.dart into one file, it still doesn't work.
I solved this issue by having the global navigator key in a separate file. Then I used that in my materialApp and in the middleware.
I put the navigator key in my keys.dart file:
import 'package:flutter/widgets.dart';
class NoomiKeys {
static final navKey = new GlobalKey<NavigatorState>();
}
Added the key to MaterialApp widget "navigatorKey: NoomiKeys.navKey," in my main.dart file (alot of code is removed to make it faster to read):
import 'package:noomi_nursing_home_app/keys.dart';
#override
Widget build(BuildContext context) {
return StoreProvider<AppState>(
store: store,
child: MaterialApp(
//Add the key to your materialApp widget
navigatorKey: NoomiKeys.navKey,
localizationsDelegates: [NoomiLocalizationsDelegate()],
onGenerateRoute: (RouteSettings settings) {
switch (settings.name) {
And use it in navigate_middleware.dart;
import 'package:noomi_nursing_home_app/actions/actions.dart';
import 'package:noomi_nursing_home_app/keys.dart';
import 'package:redux/redux.dart';
import 'package:noomi_nursing_home_app/models/models.dart';
List<Middleware<AppState>> navigateMiddleware() {
final navigatorKey = NoomiKeys.navKey;
final navigatePushNamed = _navigatePushNamed(navigatorKey);
return ([
TypedMiddleware<AppState, NavigatePushNamedAction>(navigatePushNamed),
]);
}
Middleware<AppState> _navigatePushNamed(navigatorKey) {
return (Store<AppState> store, action, NextDispatcher next) {
next(action);
navigatorKey.currentState.pushNamed(action.to);
};
}
looks like you forgot to declare & pass navigatorKey to middleware
final navigatorKey = GlobalKey<NavigatorState>();
void main() {
final store = Store(appStateReducer,
middleware:createRouteMiddleware(navigatorKey: navigatorKey)
);
runApp(MyApp(store));
}
and your MaterialApp is missing navigatorKey too
MaterialApp(
navigatorKey: navigatorKey
routes: /* your routes */
)

Resources