A library that connects Widgets to a Redux Store

Overview

flutter_redux

Build Status codecov

A set of utilities that allow you to easily consume a Redux Store to build Flutter Widgets.

This package supports null-safety and is built to work with Redux.dart 5.0.0+.

Redux Widgets

  • StoreProvider - The base Widget. It will pass the given Redux Store to all descendants that request it.
  • StoreBuilder - A descendant Widget that gets the Store from a StoreProvider and passes it to a Widget builder function.
  • StoreConnector - A descendant Widget that gets the Store from the nearest StoreProvider ancestor, converts the Store into a ViewModel with the given converter function, and passes the ViewModel to a builder function. Any time the Store emits a change event, the Widget will automatically be rebuilt. No need to manage subscriptions!

Examples

  • Simple example - a port of the standard "Counter Button" example from Flutter
  • Github Search - an example of how to search as a user types, demonstrating both the Middleware and Epic approaches.
  • Todo app - a more complete example, with persistence, routing, and nested state.
  • Timy Messenger - large open source app that uses flutter_redux together with Firebase Firestore.

Companion Libraries

Usage

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

Note: This example requires flutter_redux 0.4.0+ and Dart 2! If you're using Dart 1, see the old example.

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

// One simple action: Increment
enum Actions { Increment }

// The reducer, which takes the previous count and increments it in response
// to an Increment action.
int counterReducer(int state, dynamic action) {
  if (action == Actions.Increment) {
    return state + 1;
  }

  return state;
}

void main() {
  // Create your store as a final variable in the main function or inside a
  // State object. This works better with Hot Reload than creating it directly
  // in the `build` function.
  final store = Store<int>(counterReducer, initialState: 0);

  runApp(FlutterReduxApp(
    title: 'Flutter Redux Demo',
    store: store,
  ));
}

class FlutterReduxApp extends StatelessWidget {
  final Store<int> store;
  final String title;

  FlutterReduxApp({Key key, this.store, this.title}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // The StoreProvider should wrap your MaterialApp or WidgetsApp. This will
    // ensure all routes have access to the store.
    return StoreProvider<int>(
      // Pass the store to the StoreProvider. Any ancestor `StoreConnector`
      // Widgets will find and use this value as the `Store`.
      store: store,
      child: MaterialApp(
        theme: ThemeData.dark(),
        title: title,
        home: Scaffold(
          appBar: AppBar(
            title: Text(title),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                // Connect the Store to a Text Widget that renders the current
                // count.
                //
                // We'll wrap the Text Widget in a `StoreConnector` Widget. The
                // `StoreConnector` will find the `Store` from the nearest
                // `StoreProvider` ancestor, convert it into a String of the
                // latest count, and pass that String  to the `builder` function
                // as the `count`.
                //
                // Every time the button is tapped, an action is dispatched and
                // run through the reducer. After the reducer updates the state,
                // the Widget will be automatically rebuilt with the latest
                // count. No need to manually manage subscriptions or Streams!
                StoreConnector<int, String>(
                  converter: (store) => store.state.toString(),
                  builder: (context, count) {
                    return Text(
                      'The button has been pushed this many times: $count',
                      style: Theme.of(context).textTheme.display1,
                    );
                  },
                )
              ],
            ),
          ),
          // Connect the Store to a FloatingActionButton. In this case, we'll
          // use the Store to build a callback that will dispatch an Increment
          // Action.
          //
          // Then, we'll pass this callback to the button's `onPressed` handler.
          floatingActionButton: StoreConnector<int, VoidCallback>(
            converter: (store) {
              // Return a `VoidCallback`, which is a fancy name for a function
              // with no parameters and no return value. 
              // It only dispatches an Increment action.
              return () => store.dispatch(Actions.Increment);
            },
            builder: (context, callback) {
              return FloatingActionButton(
                // Attach the `callback` to the `onPressed` attribute
                onPressed: callback,
                tooltip: 'Increment',
                child: Icon(Icons.add),
              );
            },
          ),
        ),
      ),
    );
  }
}

Purpose

One question that reasonable people might ask: Why do you need all of this if StatefulWidget exists?

My advice is the same as the original Redux.JS author: If you've got a simple app, use the simplest thing possible. In Flutter, StatefulWidget is perfect for a simple counter app.

However, say you have more complex app, such as an E-commerce app with a Shopping Cart. The Shopping Cart should appear on multiple screens in your app and should be updated by many different types of Widgets on those different screens (An "Add Item to Cart" Widget on all your Product Screens, "Remove Item from Cart" Widget on the Shopping Cart Screen, "Change quantity" Widgets, etc).

Additionally, you definitely want to test this logic, as it's the core business logic to your app!

Now, in this case, you could create a Testable ShoppingCart class as a Singleton or Create a Root StatefulWidget that passes the ShoppingCart Down Down Down through your widget hierarchy to the "add to cart" or "remove from cart" Widgets.

Singletons can be problematic for testing, and Flutter doesn't have a great Dependency Injection library (such as Dagger2) just yet, so I'd prefer to avoid those.

Yet passing the ShoppingCart all over the place can get messy. It also means it's way harder to move that "Add to Item" button to a new location, b/c you'd need up update the Widgets throughout your app that passes the state down.

Furthermore, you'd need a way to Observe when the ShoppingCart Changes so you could rebuild your Widgets when it does (from an "Add" button to an "Added" button, as an example).

One way to handle it would be to simply setState every time the ShoppingCart changes in your Root Widget, but then your whole app below the RootWidget would be required to rebuild as well! Flutter is fast, but we should be smart about what we ask Flutter to rebuild!

Therefore, redux & redux_flutter was born for more complex stories like this one. It gives you a set of tools that allow your Widgets to dispatch actions in a naive way, then write the business logic in another place that will take those actions and update the ShoppingCart in a safe, testable way.

Even more, once the ShoppingCart has been updated in the Store, the Store will emit an onChange event. This lets you listen to Store updates and rebuild your UI in the right places when it changes! Now, you can separate your business logic from your UI logic in a testable, observable way, without having to Wire up a bunch of stuff yourself!

Similar patterns in Android are the MVP Pattern, or using Rx Observables to manage a View's state.

flutter_redux simply handles passing your Store down to all of your descendant StoreConnector Widgets. If your State emits a change event, only the StoreConnector Widgets and their descendants will be automatically rebuilt with the latest state of the Store!

This allows you to focus on what your app should look like and how it should work without thinking about all the glue code to hook everything together!

Contributors

Comments
  • Error after updating to 0.4.0

    Error after updating to 0.4.0

    Hey @brianegan

    after updating to 0.4.0 Im getting the following error. Any idea what could cause the issue?

    ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞══
    The following NoSuchMethodError was thrown building StoreConnector<AppState,
    Store<AppState>>(dirty):
    The getter 'store' was called on null.
    Receiver: null
    Tried calling: store
    

    flutter Doctor

    [✓] Flutter (Channel master, v0.2.4-pre.64, on Mac OS X 10.13.3 17D102, locale en-DE)
        • Flutter version 0.2.4-pre.64 at /Users/eikebartels/Applications/flutter
        • Framework revision 619ebd67a9 (5 hours ago), 2018-03-20 00:26:10 -0700
        • Engine revision c3ab0c9143
        • Dart version 2.0.0-dev.39.0.flutter-f1ebe2bd5c
    

    Main

    void main() {
      final store = new Store<AppState>(
        appStateReducer,
        initialState: new AppState.loading(),
        middleware: createStoreMiddleware()
      );
      runApp(new App(store: store));
    }
    

    App

    class App extends StatelessWidget {
      final Store store;
    
      App({Key key, this.store }) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return new StoreProvider<AppState>(
          store: store,
          child: new MaterialApp(
            theme: AppTheme.theme,
            routes: {
              "/": (context) {
                return new StoreBuilder<AppState>(
                    builder: (context, store) {
                      return new OnBoarding();
                    });
              }
            },
          ),
        );
      }
    }
    
    opened by lasseschmitt 25
  • Provide a way to use StoreBuilder/StoreConnector without using StoreProvider to get the Store

    Provide a way to use StoreBuilder/StoreConnector without using StoreProvider to get the Store

    StoreConnector and StoreBuilder (which just wraps a StoreConnector) force you to use StoreProvider to get the store they are going to listen to. But there are times when you already have a reference to the store at the time you are constructing the StoreBuilder or StoreConstructor and having them use StoreProvider to get the store is just extra work.

    For example, you might have a StoreBuilder with rebuild on change set to false because you have some buttons that need to call store.dispatch, but next to them you have a widget that needs to rebuild based on changes to part of the state. You want to only rebuild that widget when that particular part of the state changes and that is the only widget that needs to rebuild. So you wrap that widget in a store connector with distinct on. But having that StoreConnector use the StoreProvider to find the Store is unnecessary work.

    I am also looking at this because I am looking at structuring my redux so that there is a global Store with the state for the entire app and also the ability to have child Stores that are specific to a view/page and that Store only exists while that view is in existence and goes away when that view/page goes away. In this case the Store is passed to the constructor of the view/page. Having to create a StoreProvider to provide the Store is extra hassle since the Store is stored in the state of the view/page. One of the justifications for this hierarchical state is that you might have multiple of these views on screen at the same time and they each need their own state.

    So one way to handle this is to have an optional store parameter on StoreBuilder/StoreConnector that if set is the store that is listened to. If it is not set use StoreProvider.

    Or alternatively it could be a storeProvider parameter which is function from BuildContext to Store and it has a default value which is to call StoreProvider.

    Alternatively, I would be equally satisfied if _StoreStreamListener were simply made public, since StoreConnector is nothing more than a shallow wrapper around _StoreStreamListener that only adds the call to get the Store from StoreProvider and some asserts on parameters.

    opened by dalewking 16
  • Scrolling down to bottom of screen when Redux store changes

    Scrolling down to bottom of screen when Redux store changes

    Hi Brian,

    I'm trying to build a small chat app with Redux, and when new list items (chat messages) are added to the store I want to animate a scroll down to the bottom of the list so they are in view.

    Without Redux, in Flutter you're able to use ScrollController then call _scrollController.animateTo when you call setState to add the new items (source).

    In React, you would have componentDidUpdate, so you would be able to animate the scroll to the bottom in componentDidUpdate when your Redux store changes (source).

    Wondering what is the equivalent way to do this in Redux with Flutter since StatelessWidget doesn't provide hooks like componentDidUpdate? Unfortunately, just calling _scrollController.animateTo after dispatching a Redux action doesn't scroll to the bottom position after the Redux store updates.

    enhancement 
    opened by hash404 15
  • Accessing store in StoreConnector.builder

    Accessing store in StoreConnector.builder

    Hi,

    I need to have access to the store in the builder function so I can dispatch calls to the middleware. Is there a way to do this "nicely" without storing the store during the call to onInit?

    I am new to dart and I just cannot see how to do this.

    The use case I am looking at is having a widget display some stateful data and a button. The button when pressed should invoke the store.dispatch(new SomeAction());

    Paul

    opened by Paul-Todd 14
  • Error: No StoreProvider<AppState> found. To fix, please try: * Using Dart 2 (required) by using the --preview-dart-2 flag * Wrapping your MaterialApp with the StoreProvider<State>, rather than an individual Route *

    Error: No StoreProvider found. To fix, please try: * Using Dart 2 (required) by using the --preview-dart-2 flag * Wrapping your MaterialApp with the StoreProvider, rather than an individual Route *

    Time to time getting Crashlytcis report like this:

    Non-fatal Exception: package:flutter_redux/flutter_redux.dart 29 in StoreProvider.of Error: No StoreProvider<AppState> found. To fix, please try: * Using Dart 2 (required) by using the --preview-dart-2 flag * Wrapping your MaterialApp with the StoreProvider<State>, rather than an individual Route * Providing full type information to your Store<State>, StoreProvider<State> and StoreConnector<State, ViewModel> If none of these solutions work, please file a bug at: https://github.com/brianegan/flutter_redux/issues/new

    Note: In the app regulary using the Redux and it works fine.

    Here is the app snippet:

    import 'dart:async';
    import 'package:driveddy/app/app_state.dart';
    import 'package:driveddy/app/app_state_reducer.dart';
    import 'package:driveddy/app/middleware.dart';
    import 'package:driveddy/app/routes.dart';
    import 'package:driveddy/app/theme.dart';
    import 'package:driveddy/localization/fallback_cupertino_localization_delegate.dart';
    import 'package:driveddy/values/keys.dart';
    import 'package:flutter/cupertino.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter_app_badger/flutter_app_badger.dart';
    import 'package:flutter_localizations/flutter_localizations.dart';
    import 'package:flutter_redux/flutter_redux.dart';
    import 'package:redux/redux.dart';
    
    class App extends StatefulWidget {
      @override
      _AppState createState() => _AppState();
    }
    
    class _AppState extends State<App>  {
      
      static Store<AppState> store = new Store<AppState>(
        appStateReducer,
        initialState: new AppState.loading(),
        middleware: createMiddleware(),
      );
    
      @override
      Widget build(BuildContext context) {
        return new StoreProvider<AppState>(
          store: store,
          child: new StoreConnector<AppState, _ViewModel>(
            converter: _ViewModel.fromStore,
            distinct: true,
            builder: (context, vm) {
              return new MaterialApp(
                localeResolutionCallback: (deviceLocale, supportedLocales) {
                  return deviceLocale;
                },
                localizationsDelegates: [
                  GlobalMaterialLocalizations.delegate,
                  GlobalWidgetsLocalizations.delegate,
                  const FallbackCupertinoLocalizationsDelegate(),
                ],
                showPerformanceOverlay: vm.isDebug,
                navigatorKey: Keys.navigator,
                theme: AppTheme.theme,
                initialRoute: Routes.initialRoute,
                routes: Routes.routes(context),
              );
            },
          ),
        );
      }
    }
    

    This is the screen where the issue is happening:

    @override
     Widget build(BuildContext context) {
       _setIsDisposable(context: context, isDisposable: false);
         return  new Text(
                       "some text",
                       textAlign: TextAlign.center,
                       maxLines: 4,
                       style: new TextStyle(fontSize: 16.0, height: 1.25, color: AppTheme.gray7),
                     );
     }
    
     void _setIsDisposable({@required BuildContext context, @required bool isDisposable}) {
       StoreProvider.of<AppState>(context).dispatch(new SetIsSignUpStackDisposableAction(isDisposable: isDisposable));
     }
    
    

    Doctor summary (to see all details, run flutter doctor -v):

    [✓] Flutter (Channel beta, v1.0.0, on Mac OS X 10.13.6 17G65, locale en-DE)
    [✓] Android toolchain - develop for Android devices (Android SDK 28.0.3)
    [✓] iOS toolchain - develop for iOS devices (Xcode 10.1)
    [✓] Android Studio (version 3.3)
    [!] VS Code (version 1.30.2)
    [✓] Connected device (1 available)
    
    opened by Abgaryan 12
  • onInitialBuild called multiple time on child container when parent container changes

    onInitialBuild called multiple time on child container when parent container changes

    Hi all, I have a question regarding container that have other container. Basically I have a container that can display loading status and error message. It is a sort of "shell" container. On this container I have a child container with its own viewmodel and nothing shared. I can see the onInitialBuild method on the child container is called every time the mainshell onInitialBuild is changed. Is this an expected behavior?

    opened by AlexandreRoba 12
  • How do I dispatch actions to the Store without building a widget?

    How do I dispatch actions to the Store without building a widget?

    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 returns void (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.

    opened by jeroen-meijer 12
  • Fix StoreProvider.of for Reified types

    Fix StoreProvider.of for Reified types

    I'm repeatedly getting

    I/flutter ( 9311): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
    I/flutter ( 9311): The following NoSuchMethodError was thrown building StoreConnector<int, Store<int>>(dirty):
    I/flutter ( 9311): The getter 'store' was called on null.
    I/flutter ( 9311): Receiver: null
    I/flutter ( 9311): Tried calling: store
    

    error when trying to use StoreBuilder or StoreConnector in the hierarchy. My app widget builds the rest like this:

    @override
    Widget build(BuildContext context) {
      return new StoreProvider<int>(
        store: new Store<int>(
                (i, action) => i + 1,
            initialState: 0
        ),
        child: new MaterialApp(
          title: 'App',
          theme: new ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: new Scaffold(
              appBar: new AppBar(
                title: new Text("App"),
              ),
              body: new MainScreen(),
        ),
      );
    }
    

    I can't get it to work, I understand StoreProvider is a simple InheritedWidget, but even if I try to manually call new StoreProvider.of(context) in a widget down the tree, I get null. I don't understand, since I've created dead simple inherited widget and placed it instead of StoreProvider and I could fetch it with of() method without issues (I almost did a copy-paste from the StoreProvider class).

    The int state and inline reducer is just a result of me trying to simplify the things as much as I can, with no luck. Any idea why would it be like this?

    opened by lwasylkowski 12
  • Using flutter redux and Refresh Indicator

    Using flutter redux and Refresh Indicator

    Hi,

    Great library, I've really enjoyed implementing it but I've had a bit of a mammoth session and can't seem to wrap my head around this one. I am pretty new to Flutter and Dart so apologies if this is a simple question.

    I want to use a pull to refresh which sends an action and retrieves a new set of items from the web via the middleware. Doing this without the refresh indicator works well, but the indicator needs a Future passed to it that resolves when the action has finished. Is there any way that I can use the existing stock widget to start and stop based on actions?

    Thanks

    opened by oli107 12
  • Options for persistence relating to where we put our business logic and using middleware.

    Options for persistence relating to where we put our business logic and using middleware.

    Hi Brian, many thanks for the library once again 👍

    What options do we have / what recomendations can you give for persistance? The main problem I'm having is that I put a lot of my business logic in my reducers. This seemed to be working out until I tried to add some persistence middleware

    1. dispatch(new CalculatePersonsAgeAction);
    2. middleware - persist data
    3. reducer - run calculate age logic and update record in the store

    (as you can probably work out the persist will be calculated too early and will save old information, also some of my actions just pass an id such as the following action so I need to lookup the record...

    ToggleExcludedAction(int myId)

    this is handled in my reducer where I look up the object and do a copyWith to alter my record.

    So this was my first problem, I am running my logic before I need to persist it, so...my next plan was to put more of my logic in my actions and I started to use redux thunk where it was necessary to get at the state (ie lookup an existing record by id). My next problem is that now my actions are tied to AppState and my tests aren't as clean becase I need to create AppState (previously I could create a simple Store based on just the data relevant to the reducer).

    ...here is the new Action...

    Function(Store<AppState>) toggleExcludedAction(int myId) {
      return (Store<AppState> store) {
    

    which I feel makes it a little less clear in the test because now I have to create the AppState in my tests where a lot of the data is irrelevant to the test (previously I was just creating just the data that the reducer was based on which made it clear what the data dependencies were). It's not the end of the world but it's just not as clean and wondered if I had missed something or if there is an alternative option.

    I'm now considering just putting the code into a function that accepts the required dependencies and letting the action (which has a dependency on AppState) call that function and only testing my function.

    so I test this

    void userFlagSeen(Function(dynamic) dispatch, List<UserFlag> userFlags, int id) {
      var existingUserFlag = userFlags.firstWhere((uf) => uf.id == id);
      var newUserFlag = existingUserFlag.copyWith(hasSeen: true);
      dispatch(new UserFlagUpdateA(newUserFlag));
    }
    

    but not this

    Function(Store<AppState>) userFlagSeenAction(int lectureId) {
      return (Store<AppState> store) =>
          _userFlagSeenAction(store.dispatch, store.state.userFlags, lectureId);
    }
    

    ok...now I'm overthinking this problem but here is a more type safe class based approach

    class Action<T>{
      Function(Store<AppState>) byId(Actions<T> actions, int id) {
        return (Store<AppState> store) =>
            actions.updateAction(store.dispatch, new T().storeStateFn, id);
      }
    }
    
    abstract class Actions<T> {
      void updateAction(Function dispatch, List<T> objects, int id);
    }
    
    class HasSeen implements Actions<UserFlag> {
      @override
      void updateAction(Function dispatch, List<UserFlag> userFlags, int id) {
        var newUserLecture = new UserFlag(id, true);
        dispatch(new UserFlagUpdateAction(newUserLecture));
      }
    }
    

    calling it like so

    dispatch(new Action<UserFlag>().byId(new HasSeen(), 1))

    there may be an easier way to this though!

    awaiting reply 
    opened by atreeon 11
  • The getter 'store' was called on null

    The getter 'store' was called on null

    Hi,

    I'm trying to implement redux on my flutter app, versions:

      redux: "^3.0.0"
      flutter_redux: "^0.5.0"
    

    When I run my app the error in the title is thrown. I followed the Dart 2 migration guide for both the packages.

    Flutter: 0.2.8 Dart: 2.0.0

    opened by darioielardi 10
  • [Question]: Any thoughts on difference between ignoreChange and distinct?

    [Question]: Any thoughts on difference between ignoreChange and distinct?

    Hi, new dart beginner here. As far as I can see, the widget update process will spawn a stream which could be cancelled both when ignoreChange implemented, and distinct is set true. I'm not seeing any difference using one of the two, and confused about it. Not sure if there is any consideration I've missed?

      void _createStream() {
        _stream = widget.store.onChange
            .where(_ignoreChange)
            .map((_) => widget.converter(widget.store))
            .transform(StreamTransformer.fromHandlers(
              handleError: _handleConverterError,
            ))
            // Don't use `Stream.distinct` because it cannot capture the initial
            // ViewModel produced by the `converter`.
            .where(_whereDistinct)
            // After each ViewModel is emitted from the Stream, we update the
            // latestValue. Important: This must be done after all other optional
            // transformations, such as ignoreChange.
            .transform(StreamTransformer.fromHandlers(
              handleData: _handleChange,
            ))
            // Handle any errors from converter/onWillChange/onDidChange
            .transform(StreamTransformer.fromHandlers(
              handleError: _handleError,
            ));
      }
    
    opened by Fnll 0
  • Question on how to use the reducer right way

    Question on how to use the reducer right way

    I am working on redux for state management and using MVVM architecture. 

I have made a generic reducer that only returns the updated store. For each feature I make a class, let’s call it a sub-store, and make this class in AppStore as a data member to maintain its own state. Now for each sub-store, I made a reducer that extends the generic reducer for common operations. My generic reducer takes the old sub-store and takes the new sub-store as action and depending on the API state e.g. (‘isLoading’, ’success’), updates the store. Since reducers are supposed to have logic. I am processing and calculating the new sub-store state either in thunkAction or in ViewModel and dispatching the Action only when the new sub-store is ready to be updated. Let's say I want to update the data member isNewUser. I will do this in ThunkAction:

    
UserLoginStore loginStore = store.state.userLoginStore.copyWith(isNewUser: true);
    store.dispatch(ApiResponseAction<UserLoginStore>(apiResState: ApiResState.success, updateStore: loginStore));


    

    Am I doing it right? In this way, the reducer does not have much logic despite some specific functionalities that may be required by a specific sub-store. 
 As it can be seen in the above snippet I created an instance of UserLoginStore and kept the updated store in that and then dispatched the action to the reducer where the actual state will be updated for the application.

    // sub-store
class 
    UserLoginStore {
      final UserModel userModel;
      final bool isNewUser;
      final ApiResState apiResState;
    }
    
    
    //main store
    class AppStore {
      final QueriesStore queriesStore;
      final UserLoginStore userLoginStore;
      final UserExistsModel userExistsStore;
    }
    
    
    //generic Action 
    class ApiResponseAction<T> {
      ApiResState apiResState;
      T? updateStore; //only populated if response is a success
    
      ApiResponseAction({required this.apiResState, this.updateStore});
    }
    
    
    // generic reducer
    abstract class AppStateReducer<T> {
      T apiResponse(state, ApiResponseAction<T> action) {
        switch (action.apiResState) {
            case ApiResState.isLoading:
            return state!.copyWith(apiResState: action.apiResState);
    
          case ApiResState.success:
            return action.updateStore == null
                ? state.copyWith(apiResState: action.apiResState)
                : action.updateStore;
        }
      }
    
      Reducer<T> get apiResponseReducer => combineReducers<T>([
            TypedReducer<T, ApiResponseAction<T>>(apiResponse),
          ]);
    }
    
    
    opened by Lyba97 2
  • Passing Store as an argument to MethodChannel and Background Isolate

    Passing Store as an argument to MethodChannel and Background Isolate

    I want to pass Redux store as an argument to MethodChannel in Flutter. Here the work of native side is to spawn a new isolate and perform Headless Code execution. This background isolate needs access to the main store which is being updated in main isolate. Any help would be most welcomed. Also I am not using any plugins like WorkManager etc. Thanks

    opened by abhineetchandan 0
  • Import Store data type

    Import Store data type

    Hi there,

    First of all, thank you for the wonderful tool. I like it even more than the original JS Redux ,with the support for enums for actions and with Dart's strong typing which allows code suggestions while typing.

    The one request I have is about exposing the Store class used with Redux so it can be imported. I will try to show the code that I currently have after mentioning these benefits I see from doing this.

    1. Can pass store as a function parameter with strong typing. (If I try passing a store as a function parameter now, it has to be of type dynamic which can break depending on other developers.
    2. Better code suggestions from IDE compared to using type dynamic.

    I hope that makes sense. Thanks for your time, and once again, for my favourite way of managing state with Flutter.

    PS: Side question I hope you don't mind.

    If I have multiple forms that I would like to use Redux for, is it better to have:

    1. An ephemeral store for each form separate from the global app state (possibly a better memory optimisation, at the cost of architectural complexity), or
    2. A single global app state with each form data class being nullable and set to null once the form data has been submitted.

    EDIT: I have a function like this, which is called in a loop.

    double calculateDistanceFromUser(dynamic store, LatLng inputPoints) {
      const Distance geo = Distance();
      return geo.as(
        LengthUnit.Kilometer,
        inputPoints,
        LatLng(
          store.state.userLocation.latitude,
          store.state.userLocation.longitude,
        ),
      );
    }
    

    My two choices are to look up the store from the build context each loop iteration (unnecessary computation) or to use type dynamic to represent the store, neither of which is desirable.

    opened by hummy123 0
  • [Question]: Mixing global and local state

    [Question]: Mixing global and local state

    Using the StoreConnector it looks to me like all of the view models properties must be derived from the current store data. But what if I want to have some data that should be kept local to the view. Let's say I want to e.g. show an alert once based on an exception that is part of the redux state. For this, I would have a property like showedExceptionAlert in the view model. But whenever the view model gets regenerated the value of this property would get overridden. And I don't want to go the full redux way via actions, reducer... just because of a simple, local-only property.

    For sure I could keep this data in the view, but that feels a little bit wrong to have two places to look for the current state.

    Another option would be to mix e.g. the bloc pattern with redux but this also seems a little bit too much for such a simple task.

    So the question is: Is there something like a pattern to have local and global (redux) state in one view model?

    opened by hffmnn 0
  • Receive the action that caused the state update in StoreConnector hooks

    Receive the action that caused the state update in StoreConnector hooks

    Hi, I was wondering if there's a way to receive the last action that produced the state in StoreConnector.ignoreChange?

    Use case: This is for performance tuning. So we can ignore a part of the state update when we are sure that only a certain action can cause that part of the state to be changed. In this case, producing a new ViewModel could be skipped, because it is expensive.

    opened by ylilarry 0
Releases(0.6.0)
  • 0.6.0(Dec 4, 2019)

  • v0.5.4(Nov 6, 2019)

    • Bugfix: Rebuilding the Widget will always rebuild with latest data
    • Enforce pedantic lint rules
    • Docs
      • Document all public members
      • Add more examples to README
    Source code(tar.gz)
    Source code(zip)
Owner
Brian Egan
Montana boy living in Berlin, Indie Hacker, and speaker of bad German.
Brian Egan
Dart web3 - A dart library that connects and interacts with the Ethereum blockchain

dart_web3 A dart library that connects and interact with the Ethereum blockchain

p2bh 9 Sep 13, 2022
Ethers: A dart library that connects to interact with the Ethereum blockchain and inspired by ethers.js

Ethers For Flutter Ethers is a dart library that connects to interact with the Ethereum blockchain and inspired by ethers.js. Thanks to web3dart which

Hanggi 12 Oct 30, 2022
dart based login-screen that connects with Firebase Auth to enable users to sign-in

A Flutter / Firebase login screen A simple flutter/dart based login-screen that connects with Firebase Auth to enable users to sign-in/up with Email o

Pamela Nyasha Muzoma 2 Nov 20, 2021
A lightweight flutter plugin to check if your app is up-to-date on Google Play Store or Apple App Store

App Version Checker this package is used to check if your app has a new version on playstore or apple app store. or you can even check what is the lat

Iheb Briki 6 Dec 14, 2022
Phone-Store-App-UI-Flutter - Flutter Phone E-Store App UI with support for dark and light mode

Phone-Store-App-UI-Flutter - Flutter Phone E-Store App UI with support for dark and light mode

Jakub Sobański 2 Apr 30, 2022
Shoes-Store-App-UI-Flutter - Beautiful Shoes Store App UI with support for dark and light mode

Flutter Shoes Store App UI with support for dark and light mode. Flutter 2.8.1 N

Jakub Sobański 4 Nov 23, 2022
[Flutter package] An easy and quick way to check if the local app is updated with the same version in their respective stores (Play Store / Apple Store ).

Retrieve version and url for local app update against store app Android and iOS Features Using as reference packages like in_app_update , version_chec

Kauê Murakami 11 Nov 9, 2022
Flitter Hadrien Lejard Kevin SegaudFlitter [182⭐] - Glitter app by Hadrien Lejard and Kevin Segaud. It uses Redux and Jaguar.

flitter Gitter Client for Mobile made with Flutter Getting Started For help getting started with Flutter, view our online documentation. Configuration

null 187 Dec 8, 2022
Flutter app backed by Redux, shows animations, internationalization (i18n), ClipPath, fonts and others...

A Flutter tourism app that is backed-by Redux, shows animations, internationalization (i18n, English <=> Arabic), ClipPath, and fonts. YouTube demo I

Abdulmomen Kadum عبدالمؤمن كاظم 277 Dec 28, 2022
A simple flutter app with demo implementation of redux.

Flutter Redux Tutorial Redux Project is just a quick guide for implementation of redux.dart and flutter_redux . Written in dart using Flutter SDK. Ple

Pawan Kumar 46 Jun 16, 2022
Starter project and code generator for Flutter/Redux

Flutter Redux Starter/Code Generator Videos Short video ~ 1 minute Long video ~ 10 minutes We're using this approach to develop the Flutter app for In

Hillel Coren 278 Dec 12, 2022
Podcast app with Flutter & Redux

Podcast App - Flutter & Redux Preview Introduction I have built a basic podcast app with an interactive UI, as well as some of its functionalities : L

Bilal El Mahdaoui 31 Oct 28, 2022
A Redux version tailored for Flutter, which is easy to learn, to use, to test, and has no boilerplate

A Redux version tailored for Flutter, which is easy to learn, to use, to test, and has no boilerplate. Allows for both sync and async reducers.

Marcelo Glasberg 214 Dec 13, 2022
FlutterDux - Redux.JS driven Flutter

FlutterDux Flutter + Redux.js Android only at the moment, iOS coming soon. Getting Started Check out this article for a description of how it works. L

Paul DeMarco 6 Jul 28, 2019
Redux for Dart

Redux for Dart using generics for typed State. It includes a rich ecosystem of Docs, Middleware, Dev Tools and can be combined with Flutter using the

Flutter Community 505 Jan 8, 2023
Github Trending app built with Flutter+Redux+Built(Immutable Data)

Github Trending app built with Flutter+Redux+Built(Immutable Data)

huangyanxiong 9 May 13, 2020
Flutter-Movie - 😎 🎬 A Flutter movie app build with Fish-Redux and The Movie DB api.

movie A Flutter movie app build with Fish-Redux and TMDB api. ToDos redesign UI account detail customize stream support dark mode support localization

null 622 Dec 23, 2022
Structured and Organized Flutter (ANDROID+WEB) template project using Redux architecture and Retrofit rest package

flutter_redux_template A new Flutter project. JSON Models classes need this lines to json generator: part 'foo.g.dart'; //on imports factory Foo.from

Raul Abreu 2 Apr 11, 2022
Flutter-Movie - A Flutter movie app build with Fish-Redux na TMDB api

the applikation A Flutter movie app build with Fish-Redux na TMDB api. ToDos redesign UI account detail customize stream support dark mode support loc

Dominique Rwema Bagirishya 27 Jul 21, 2022
This Dart package offers developers a streamlined library of Flutter widgets, useful for expanding widgets and text views, when users interact with them.

This Dart package offers developers a streamlined library of Flutter widgets, useful for expanding widgets and text views, when users interact with them.

Jesús Rodríguez 44 Dec 6, 2022