Closed Lilja closed 1 year ago
Example:
import 'package:flutter/material.dart';
import 'package:redux/redux.dart';
enum Actions { increment }
int counterReducer(int state, dynamic action) {
return action == Actions.increment ? state + 1 : state;
}
void main() {
runApp(StoreProvider<int>(
child: MaterialApp(
home: Scaffold(
body: StoreConnector<int, VoidCallback>(
builder: (context, vm) {
print("render");
vm();
return const Text("data");
},
converter: (store) => () => store.dispatch("Foo")))),
store: store));
}
Restarted application in 927ms.
2064 I/flutter (17550): render
Application finished.
Exited (sigterm)
I believe you're looking for the onInit
callback function which can be passed to the StoreConnector
constructor.
https://pub.dev/documentation/flutter_redux/latest/flutter_redux/StoreConnector/onInit.html
If you dispatch an action inside the builder
function, it will send that action to the Redux reducer, which triggers a state change, which triggers a rebuild, which runs the builder
function, which dispatches again, which calls the recuer, produces a state changes, calls the builder... and you've found yourself in an infinite loop :)
Some sample code below (might be missing a paren somewhere -- github coding and didn't run it locally, but should get the idea across).
import 'package:flutter/material.dart';
import 'package:redux/redux.dart';
enum Actions { increment }
int counterReducer(int state, dynamic action) {
return action == Actions.increment ? state + 1 : state;
}
void main() {
runApp(StoreProvider<int>(
store: store
child: MaterialApp(
home: Scaffold(
body: StoreConnector<int, int>(
// Grab the current count from the store
converter: (store) => store.state,
// A function that runs once when the StoreConnector is inserted into the widget tree
onInit: (store) => store.dispatch(increment),
// Should be a pure function that returns a Widget tree and performs no side effects.
builder: (context, counter) {
return const Text("current count $counter");
},
),
),
);
}
Thanks @brianegan totally forgot onInit. It solves what i'm trying to do.
However, is it intended that when new state and old state is being reduced will still produce a rerender? Isn't that a bit wasteful?
That's not quite how it works, perhaps my explanation was bad. The store only emits change events after the reducer produced a new state.
After you dispatch an action, the action goes through the middleware, then through the reducer, which produces a new state. After the new state is produced, the store emits a change event. The StoreConnector listens to those change events and runs the builder function to produce a new widget tree.
In Flutter, we do not have hooks, therefore builders / widget build methods are intended to be pure functions without side effects.
If you want to avoid a rebuild, you need to ensure the view model you emit implements the == method and pass the distinct: true option to the StoreConnector.
On Sat, Mar 4, 2023 at 02:12 Erik Lilja @.***> wrote:
Thanks @brianegan https://github.com/brianegan totally forgot onInit. It solves what i'm trying to do.
However, is it intended that when new state and old state is being reduced will still produce a rerender? Isn't that a bit wasteful?
— Reply to this email directly, view it on GitHub https://github.com/brianegan/flutter_redux/issues/243#issuecomment-1454672603, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAA65DA5LWZAZKGLDYHJ6HDW2MBQDANCNFSM6AAAAAAVPFOIZE . You are receiving this because you were mentioned.Message ID: @.***>
Thanks! I'll have a look and reach out if I need more help. Much appreciated.
Very new to flutter.
I'm currently experiencing something which is weird in my book. I have a store that I'm connecting. Because of the lack of
onMounted
or equivalent in react(coming from vue) I would like to trigger a side effect once when the widget renders. To do this I tried to dispatch something and then catch is as a middleware. But something is not working I feel like.My widget is essentially this:
Looking at
pingSubreddit
, you get this:store.dispatch(5)
. The reducer is checking the action type and performing logic accordingly. There is nothing that is supposed to happen when an integer is passed.For some reason, this is rendering an infinite loop. I suppose that this package will always take a reducer and render the new components below it. Is this intended? I tried to replicate this using React's redux package by doing a dispatch during render. But it doesn't look like that forces an infinite loop.