Is it okay to write code logic (if, for, while) inside your build method - flutter

I have some data that I need to show in the UI based on the date of the running time
so I'm doing something like this inside my build method after getting my data from the Consumer Widget
DateTime dateTomorrow =
DateTime.now().add(const Duration(days: 1));
String tomorrowDay =
constants.dayFormat.format(dateTomorrow);
isWhileTrue = true;
while (isWhileTrue) {
if (myMainProgram.isDayShown(tomorrowDay)) {
isWhileTrue = false;
} else {
dateTomorrow =
dateTomorrow.add(const Duration(days: 1));
tomorrowDay =
constants.dayFormat.format(dateTomorrow);
}
}
I felt that there is something wrong with my way of handling data and writing some code logic inside my build method but I couldn't think of any other way to do it.
So is it wrong to write things like this inside your main function? and if not what are my other options?

No Its not okay to do like this because when ever the build function would rebuild by setState the data will revert.
The best way is to calculate in initState funtion.
InitState is the first function that is called when the widget is build and it runs once.
void initState(){
super.initState();
..your logic
}

Related

For Flutter, is it better to wrap only actual changes with setState()?

Is there a difference between wrapping the entire function and only wrapping the actual changes with setState()?
wrapping the entire function
setState(() {
if (switchValueAdd) {
valueAdd.text = (int.parse(num1) + int.parse(num2)).toString();
} else {
valueAdd.text = '';
}
});
wrapping only actual changes
if (switchValueAdd) {
setState(() {
valueAdd.text = (int.parse(num1) + int.parse(num2)).toString();
});
} else {
setState(() {
valueAdd.text = '';
});
}
Is there any difference in terms of performance between the above two code snippets?
Any help will be appreciated!
Also, with if-else statements, does 'else' cost as much memory as 'if'?
In other words, is 'else' basically the same as 'if' but checking if otherwise is true?
Thank you for your effort and time in advance!
Functionally, putting non-asynchronous code within the setState or putting it outside will result in very close to the same result. What you should try to avoid is having a huge block of code within the setState as this could be hard to read.
If you look at the source code for the setState method, it is just calling the function and doing a few asserts, so if you are doing the same amount of calls to it, it shouldn't have any appreciable difference. Theoretically, it could be very slightly slower if you are accessing local variables from within the closure, as those variables (or at least the references to them) could need to be copied through the stack into the function, but the actual overhead that will result in would need someone with a more complete understanding of dart's compiler for various platforms to fully explore.
Realistically, in terms of actual real-world performance, it's very unlikely to matter. There are probably other optimizations in your code which would result in much larger performance variance than this.
Also, from the setState documentation:
Generally it is recommended that the setState method only be used to wrap the actual changes to the state, not any computation that might be associated with the change. For example, here a value used by the build function is incremented, and then the change is written to disk, but only the increment is wrapped in the setState:
Future<void> _incrementCounter() async {
setState(() {
_counter++;
});
Directory directory = await getApplicationDocumentsDirectory();
final String dirName = directory.path;
await File('$dir/counter.txt').writeAsString('$_counter');
}
I would focus more on legibility in this case - whichever version you find easier to read is probably the one that will serve you best.
I'd probably write it like this:
setState(() {
valueAdd.text =
switchValueAdd ? (int.parse(num1) + int.parse(num2)).toString() : '';
});
It is not difference. setState called only in one case (from if or else, not from both). But if you will have to write readable code, use first variant because it is more readable. And statements is not a high-performance operation.
You can also simplify thin:
valueAdd.text = switchValueAdd
? (int.parse(num1) + int.parse(num2)).toString()
: valueAdd.text = '';
You can refresh state after executing all code of function so, it will reduce refresh build many times and improve performance of app.
valueAdd.text = switchValueAdd
? (int.parse(num1) + int.parse(num2)).toString()
: valueAdd.text = '';
/* All your other code which is need to manage state */
setState((){}); // call after all code executed of function

GetX Unbind Stream

I am using the bindStream() function with the GetX package inside a controller.
class FrediUserController extends GetxController {
#override
void onReady() {
super.onReady();
final userController = Get.find<FrediUserController>();
var groupIds = userController.user.groups;
groupList.bindStream(DatabaseManager().groupsStream(groupIds));
ever(groupList, everCallback);
}
}
But, when the groupIds update in the FrediUserController (with an ever function that gets triggered, I want to RE-bind the streams. Meaning, delete the existing ones and bind again with new ids, or replace the ones that have changed.
Temporary Solution: Inside ever() function
Get.delete<FrediGroupController>();
Get.put(FrediGroupController());
This code gets run everytime my groupIds change from the database. But I do not want to initiate my controllers every time a small thing changes, it is bad UX.
This seems difficult, could someone guide me to the right direction? Maybe there is a completely different approach to connecting two GetX controllers?
Note: the first one include editing the source code of the Getx package.
first:
looking in the source code of the package :
void bindStream(Stream<T> stream) {
final listSubscriptions =
_subscriptions[subject] ??= <StreamSubscription>[];
listSubscriptions.add(stream.listen((va) => value = va));
}
here is what the bind stream actually do, so if we want to access the listSubscriptions list, I would do:
final listSubscriptions;
void bindStream(Stream<T> stream) {
listSubscriptions =
_subscriptions[subject] ??= <StreamSubscription>[];
listSubscriptions.add(stream.listen((va) => value = va));
}
now from your controller you will be able to cancel the streamSubscription stored in that list with the cancel method like this :
listSubscriptions[hereIndexOfThatSubscription].cancel();
then you can re-register it again with another bindStream call
second :
I believe also I've seen a method called close() for the Rx<T> that close the subscriptions put on it, but I don't know if it will help or not
Rx<String> text = ''.obs;
text.close();
I've also run into this issue, and there appears to be no exposed close function. There is a different way to do it though, using rxdart:
import 'package:get/get.dart';
import 'package:rxdart/rxdart.dart' hide Rx;
class YourController extends GetxController {
final value = 0.obs;
final _closed = false.obs;
void bindValue(Stream<int> valueStream) {
_closed
..value = true
..value = false;
final hasClosed = _closed.stream.where((c) => c).take(1);
value.bindStream(
valueStream.takeUntil(hasClosed)
);
}
}
Whenever you want to unbind, just set _closed.value = true.

dart - How to listen for Text-Change in Quill text Editor (Flutter)

I am only familiar with HTML/CSS/JS, and basics of dart/flutter
Developer Level: Beginner
Project type & language: I am developing a notes app for myself, using flutter.
My aim is to save my note, as soon as I update the text... for which I need to use a dart Function to run on every 'text-change' event..
How do I use the Text-Changes event of Quill Editor to detect changes in the Content
THE EQUIVALENT OF THIS IN JAVASCRIPT IS GIVEN BELOW , BUT I DON'T KNOW HOW TO DO IT DART & FLUTTER.
quill.on('text-change', function(delta, oldDelta, source) {
if (source == 'api') {
console.log("An API call triggered this change.");
} else if (source == 'user') {
console.log("A user action triggered this change.");
}
});
You can listen to quill document changes stream and handle it accordingly.
_controller.document.changes.listen((event) {
print(event.item1); //Delta
print(event.item2); //Delta
print(event.item3); //ChangeSource
});
I am also run into this issue. After some hours of research, I found a solution. You habe to add a listener to your QuillController, which will be called on each editor event, like pressed keys or toolbar actions.
Use the initState() method in your State class for adding a listener.
class _TextEditorState extends State<TextEditor> {
final QuillController _controller = QuillController.basic();
#override
void initState() {
_controller.addListener(() {
print('Here I am, rock me like a hurricane!!!');
});
super.initState();
}
#override
Widget build(BuildContext context) {
// Build your Widget with QuillToolbar and QuillEditor here...
}
});
Here's how it's done:
await for (final change in _quillEditorController.changes) {
final oldDelta = change.toList()[0];
final changeDelta = change.toList()[1];
final changeSource = change.toList()[2];
if (changeSource == ChangeSource.REMOTE) {
console.log("An API call triggered this change.");
} else if (changeSource == ChangeSource.LOCAL) {
console.log("A user action triggered this change.");
}
}
Note that flutter-quill's api doesn't exactly match quill.js. And since the documentation is lacking, your best hope in understanding what's available is by digging into the code-base using your editor (eg. using "go to definition").

Update a series of variable in SetState() efficiently (Dart-Flutter)

I can't find a simple way to update a series of variables in my Flutter project.
I first tried using Enums and functions to change the variables inside a setState((){}) call.
I have something like this:
void changeMode(Mode mode) {
if (mode == Mode.start) {
print('App is now in start mode');
mode = Mode.start;
bool1 = true;
bool2 = false;
bool3 = false;
color1 = kAColor1;
color2 = kAColor2;
} else if ...}
But nothing gets updated, I imagine it's due the fact that my function doesn't return anything.
If I hard code every single variable in setState((){}) it works fine, but it's absolutely inefficient and a mess to correct.
Maybe I should go with classes? Would I need to create a superclass containing all the subclasses to do something like this?
Every time that you call setState you UI will rebuild. You can use class or map to manipulate your data.
With class:
setState(() {
currentData = actualData.copyWith(bool1: false)
})
This way, you change only data that is different from currentData. On this example, I maintain all information from currentData and change only bool1 value.
Obs: copyWith is a factory that return the same type of
currentData.

Flutter Await for websocket response

Solved
I've solved this problem using a Future function and using Completer inside the function.
I am getting some Images from my server with websockets.
I have a function that emits an event with the name of the image that I need and sends an event with the Image, that is working fine, but I need my App to wait for the return of my function because my app is calling the function and trying to go to the next page without the image.
Can someone explain to me how can I make my app wait for my function to return ?
Update
I am using Stream Builder now but I can't return the data from my function.
Stream<List> getFile(List imageL) async*{
if(imageL.isNotEmpty){
List downloadedData = List();
socket.emit("PostsImagem", (imageL));
socket.on("ImagemPost", (dados) {
downloadedData = dados;
imageL = List();
});
//I can't return the downloadedData because is inside the //socket.on()
}
}