Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Call showSnackBar from middleware #44

Closed
bowojori7 opened this issue May 3, 2018 · 5 comments
Closed

Call showSnackBar from middleware #44

bowojori7 opened this issue May 3, 2018 · 5 comments

Comments

@bowojori7
Copy link

Hi, I dunno if its possible to call showSnackBar from a middleware, but I want a Snackbar to show on the active page when I catch an error. Is there a better more redux-y way of doing this?

@atreeon
Copy link

atreeon commented May 7, 2018

This got me on the right path...

https://stackoverflow.com/questions/49887690/flutter-redux-snackbar

@bowojori7
Copy link
Author

thanks for the example @twistedinferno, but I really couldn't wrap my head around how to apply this on my project. Because I call my actions from functions defined in the ViewModel of the Container and I can't access the application's context from there.

@brianegan
Copy link
Owner

Hey all, sorry about the slow response -- been traveling the past week or so. Glad ya found a solution!

@bowojori7 In that case, you can create a function in the ViewModel that takes in a context from the build method and dispatches an action with that context.

@DizWARE
Copy link

DizWARE commented Aug 25, 2018

I just want to add another idea for a solution to the original question.

Certainly, an action that passes the BuildContext, that can then be handled by your middleware will certainly work, but only in scenarios where you are coming from access to BuildContext.

In the scenario that I've been solving, I want to dispatch a snackbar message from my middleware i.e. in response to maybe an error from an async action or really any situation that a toast might be useful in response to a different action.

The best solution to solve this is a Receiver Widget. Essentially it is a widget that doesn't display anything, but is set up to react to changes in the store to do something within the build tree. You wrap your receiver around your body: property on all your scaffolds and you'll be able to receive your snackbar messages from anywhere you can dispatch an action :) The one downside is the use of temp data in your store... Maybe down the road there will be a way to handle view model updates on action dispatches instead of store updates, but it's not a big deal either way.

Here's the one I wrote. You can use this same pattern for showDialog and also the other functions under Scaffold.of(context) as well. You can even create a single receiver that chains your other receivers so it is easy to add to your pages.

import "package:flutter/material.dart";
import "package:redux/redux.dart";
import "package:flutter_redux/flutter_redux.dart";

import "../../../../actions/all.dart" show Actions;
import "../../../../models/all.dart" show AppState;
import "../../../../selectors/all.dart" show getLatestToastrMessage;

class Toastr extends StatelessWidget {
	final Widget child;

	Toastr(this.child);

	@override
	Widget build(BuildContext context) {
		return StoreConnector<AppState, _ToastrViewModel>(
			converter: (store) => _ToastrViewModel.fromStore(store),
			builder: (context, viewmodel) => child,
			onWillChange: (viewModel) {
				if (viewModel.toastToShow != null) {
					viewModel.setShowToastSuccessful();
					Scaffold.of(context).showSnackBar(viewModel.toastToShow);
				}
			},
			distinct: true,
		);
	}
}

class _ToastrViewModel {
	final Function setShowToastSuccessful;
	final SnackBar toastToShow;

	_ToastrViewModel({
		this.setShowToastSuccessful,
		this.toastToShow
	});

	static _ToastrViewModel fromStore(Store<AppState> store) {
		return _ToastrViewModel(
			setShowToastSuccessful: () => store.dispatch(Actions.toastr.showToast.success()),
			toastToShow: getLatestToastrMessage(store)
		);
	}

	@override
	int get hashCode => toastToShow.hashCode;

	@override
	bool operator ==(other) => 
		identical(this, other) ||
			other is _ToastrViewModel &&
			other.toastToShow == this.toastToShow;
}

@jimmyff
Copy link

jimmyff commented Jul 25, 2019

@DizWARE I have an issue whereby only my first screen widget seems to show my snackbars. If I click back on the Android device it shows the previous screen and this is displaying the toast messages. Both screen widgets have exactly the same code including the Toastr wrapping the Scaffold. Any ideas what is causing that? Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants