Andrea Bizzotto 💙 Profile picture
Mar 9 10 tweets 4 min read
When using GoRouter for declarative navigation, you'll often have to choose between:

- GOING to a route
- PUSHING a route

What is the difference between the two?

A thread. 🧵 Image
To start off, let's consider a simple route hierarchy made of one top route with two sub-routes. Image
Let's also define 3 pages for our routes: Image
Now, suppose that we're in the HomeScreen.

From here, we can either call `context.go('/detail')` or `context.push('/detail')`, and end up with the same result.

That is, in both cases we'll have two routes in the navigation stack (home → detail). Image
From the detail page, we can now call `context.go('/modal')` or `context.push('/modal')`.

This time the result is different:

- If we use "go", we end up with the modal page on top of the *home* page
- If we use "push", we end up with the modal page on top of the *detail* page Image
That's because "go" jumps to the target route (/modal) by *discarding* the previous route (/detail), since /modal is *not* a sub-route of /detail.

Meanwhile, "push" always adds the target route on top of the existing one, preserving the navigation stack. Image
This means that once we dismiss the modal page, we navigate back to:

- the home page, if we used "go"
- the detail page, if we used "push"

Here's a short video showing this behavior:
The bottom line?

Think of `go` as a way to *jump* to a new route. This will modify the underlying navigation stack if the new route is not a sub-route of the old one.

On the other hand, `push` will always push the destination route on top of the existing navigation stack.
For more info about GoRouter, make sure to check the official documentation (it's excellent):

gorouter.dev
I'll cover GoRouter extensively in my upcoming Flutter course, along with many other important topics.

If this is of interest, you can sign up today to secure a big discount when the course goes live. 👇

codewithandrea.com/courses/comple…

Happy coding!

• • •

Missing some Tweet in this thread? You can try to force a refresh
 

Keep Current with Andrea Bizzotto 💙

Andrea Bizzotto 💙 Profile picture

Stay in touch and get notified when new unrolls are available from this author!

Read all threads

This Thread may be Removed Anytime!

PDF

Twitter may remove this content at anytime! Save it as PDF for later use!

Try unrolling a thread yourself!

how to unroll video
  1. Follow @ThreadReaderApp to mention us!

  2. From a Twitter thread mention us with a keyword "unroll"
@threadreaderapp unroll

Practice here first or read more on our help page!

More from @biz84

Mar 16
What are some popular architectures that are suitable for Flutter App Development (and which one to choose)?

It boils down to what level of complexity you need to handle. 👇

Thread. 🧵 Image
(1/2) Model–view–controller (MVC) is a software design pattern made of 3 types of components:

- Model: directly manages the data, logic, and rules of the application
- View: UI components (widgets)
- Controller: Accepts input and converts it to commands for the model or view Image
(2/2) MVC typically overloads the model with too much logic, and an additional service layer is often added: MVC+S

The Model should be reactive (e.g. using ChangeNotifier) so that the widgets rebuild when the model changes.

And user inputs always go through the controller.
Read 14 tweets
Mar 14
What are some rules to follow for good app architecture in Flutter?

Thread. 🧵
RULE: Avoid singletons

If you want your code to be testable, there are various alternatives to singletons:

- constructor arguments (doesn't scale well with deep widget hierarchies)
- InheritedWidget or Provider
- Service locators (e.g. get_it)
RULE: Zero (or very little) business logic in the widgets.

Widgets should be as dumb as possible and only be used to map the state to the UI.

Small exceptions: sometimes I include some simple currency, date, or number formatting code in my widgets if it makes life easier.
Read 8 tweets
Mar 1
WidgetsBindingObserver is very handy for listening to changes to:

- routing events
- device orientation
- platform settings (text scale factor, brightness, locale, etc.)
- app lifecycle events

Here's how to use it to hide sensitive info when the app goes to the background. 🧵 Image
How to set it up?

- add the WidgetsBindingObserver *mixin* to one of your classes (generally a State subclass)
- register the observer inside initState (and dispose it when done) Image
Then, just override the methods for the changes you want to keep track of.

In this case, we listen to app lifecycle changes and update a "foreground" flag via setState(). Image
Read 6 tweets
Feb 28
I’ve been watching the events unfolding in #Ukraine with great concern.

And it's clear that many people need humanitarian aid, *right now*.

If you have the means to do so, donate your money (I have).

This thread lists a few non-profits helping people during this crysis. 👇
If you haven't already seen this, here's display of much needed, true leadership from the Ukranian president:

Here's a great article by @GergelyOrosz about the impact of this war on the Tech World:

Read 5 tweets
Feb 23
What are some VSCode extensions you can use to speed-up your Flutter workflow?

Here's a thread with my favourites! 🧵
When creating model classes, you'll often needs methods such as:

• copyWith()
• toString()
• toJson()
• fromJson()
• toMap()
• fromMap()
• == operator
• hashCode

Use the Dart data class generator to create them all in one go!

Link: marketplace.visualstudio.com/items?itemName…
If you use Riverpod, you'll quickly get tired of typing out all your providers and consumers by hand.

The Flutter Riverpod Snippets extension makes this a lot easier!

Link: marketplace.visualstudio.com/items?itemName…
Read 10 tweets
Feb 10
How do we apply Domain-Driven Design to exception handling?

I've been experimenting with some techniques and would love your feedback about this thread. 🧵

First of all, let's establish some goals: 👇
To define all the domain-specific exceptions, sealed unions come to hand.

Here's how we may generate Auth and Database exception types using Freezed:
Then we can define one *global* function that does two things:

- run the Future<T> that is given as an argument inside a try/catch block
- map all 3rd-party exceptions to our own exception types (and throw them)
Read 14 tweets

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just two indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3/month or $30/year) and get exclusive features!

Become Premium

Don't want to be a Premium member but still want to support us?

Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal

Or Donate anonymously using crypto!

Ethereum

0xfe58350B80634f60Fa6Dc149a72b4DFbc17D341E copy

Bitcoin

3ATGMxNzCUFzxpMCHL5sWSt4DVtS8UqXpi copy

Thank you for your support!

Follow Us on Twitter!

:(