-
Notifications
You must be signed in to change notification settings - Fork 215
How do I dispatch actions to the Store without building a widget? #51
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
Comments
Hey hey :) Trip was great, thanks! And apologies -- somehow missed this one! Overall, I'm a bit confused by this line, so my advice not be amazing: "I want some methods inside my Widgets to dispatch actions to the Store from the StoreProvider, but not necessarily build a widget." If you've got methods inside a Widget, I guess I'm thinking you'd need to instantiate / build it somewhere? Here are a couple options I could think of:
Do any of those help? If not, please feel free to write back, and it'd be great if you can describe a use-case, and I'll try to help further :) |
Thank you for your quick response :) I'll look through the links you've provided. Your second idea especially seems like it would solve my problem, but then again; passing the store to a widget might break one of the key features of redux (as you've mentioned in your DartConf 2018 talk) which is flexibility in moving classes or UI elements around and keeping things loosely coupled. In the meantime, I'll give you a use-case to further clarify my situation. Say I have a Widget that displays a button. Pressing it will then trigger a function that calls asks the database for a variable and then assigns a field of my AppState to that variable. I'm using pseudocode for the database part here. import 'package:flutter/material.dart';
// Temporary variables for demonstration purposes.
dynamic Database;
class AssignUserByDocument {AssignUserByDocument(dynamic document);}
dynamic ExampleSpecialStoreProvider;
class HomeScreen extends StatelessWidget {
void _handleButtonPressed() async {
// Make an async call to the example database.
var document = await Database.getDocument("user").byId("1234");
// This is where I want to dispatch an action to the store
// (but not build a widget, so I can't use StoreConnector, right?).
// Example solution:
ExampleSpecialStoreProvider(
converter: (store) => store,
action: (store) {
store.dispatch(new AssignUserByDocument(document));
}
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: MaterialButton(
onPressed: _handleButtonPressed,
child: Text("Initialize user object from DB!"),
),
));
}
} Now, it doesn't really matter if the I hope this is clarifying things for you. |
Thanks @jeroen-meijer, that definitely helps me understand. In this case, I'd actually recommend a slightly different path: Middleware functions should generally handle async calls in Redux. More docs: https://github.com/johnpryan/redux.dart/blob/master/doc/async.md In this case, you'll want to create a Middleware function that will listen for You can provide a function to your (Also, random side fact: your Example adapted to use Middleware: // Actions
class LoadUserSuccessAction {AssignUserByDocument(dynamic document);}
class LoadUserFailedAction {}
// Also Introduce Loading Action
class LoadUserAction(
final String id;
LoadUserAction(this.id);
);
// Create a Middleware
void loadUserMiddleware(Store<AppState> store, dynamic action, NextDispatcher next) {
if (action is LoadUserAction) {
Database.getDocument("user").byId(action.id)
.then((document) => store.dispatch(LoadUserSuccessAction(document))
.catchError((error) => store.dispatch(LoadUserFailedAction());
}
next(action);
}
AppState exampleReducer(AppState prev, dynamic action) { return prev; }
// Create your store with your middleware
final store = new Store<AppState>(exampleReducer, middleware: [loadUserMiddleware]);
class HomeScreen extends StatelessWidget {
final Function() onButtonPressed;
HomeScreen({Key key, @required this.onButtonPressed}): super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: MaterialButton(
onPressed: onButtonPressed,
child: Text("Initialize user object from DB!"),
),
),
);
}
}
// When instantiating the HomeScreen...
StoreConnector<AppState, Function()>(
converter: (store) => store.dispatch(LoadUserAction("12345")),
builder: (context, fn) => HomeScreen(onButtonPressed: fn),
); Hope that helps! |
@jeroen-meijer Did I totally blow your mind, or is that working out for ya? Let me know, or if it's safe to close this out now :) |
Gonna go ahead and close this out, please let me know if you need any further help :) |
on a similar question, how to I get store instance outside of a widget scope? currently I just save the store instance as a global static variable, however this approach feel very much like a hack. to explain the usage, consider I have a local service like component (one that listen to app lifecycle or network connectivity), which I'd like to have the ability to actively dispatch events such as onAppBackground etc. Future<Store<AppState>> createStore({BuildConfig buildConfig}) async {
initLog();
final SharedPreferences _prefs = await SharedPreferences.getInstance();
final Database _database = DatabaseImpl(_buildConfig.apiPoint);
final Recorder _recorder = RecorderImpl.initialize(database: _database);
final Store<AppState> store = Store(
appReducer,
initialState: AppState.initial(buildConfig: _buildConfig, recorder: _recorder),
distinct: true,
middleware: [
MiddlewareTest(),
RecordEntityMiddleware(database: _database),
],
);
**_recorder.store = store;**
return store;
} not exactly as a global static variable but hacky nonetheless (or is it?) |
I am having a very similar situation where my app listens to a child in my firebase database.
|
My favorite solution.
|
Yes, I had forgotten that StoreProvider is an InheritedWidget. |
@ramsanath @JuanGamarraDev How do I do this without context?
|
Nevermind. It's global in stateful widgets. I'm an idiot today I guess. |
Is there a difference between using I mean, is pretty obvious that the simpler solution is to just write the single line of code that take the store from the StoreProvider and dispatch the action but I saw in the flutter Redux Architecture Sample that they prefer to pass as a paramenter a Function that dispatch the action. Is there any difference? using StoreProvider "costs" more that just building a function in the StoreConverter ? maybebecause we already have the store in the scope in the second case? |
Hi there.
How was your trip? 😄
I've been happily using
flutter_redux
, but I'm having trouble with one thing in particular.I want some methods inside my Widgets to dispatch actions to the Store from the
StoreProvider
, but not necessarily build a widget.Since
StoreConnector()
is only intended for passing the store to a Widget in the context of the build method, I'm wondering: is there any class or function I can use inside of a method that returnsvoid
(for example) that just provides me with the Store, so I can dispatch an action to it without needing to build a widget?Thank you.
The text was updated successfully, but these errors were encountered: