Navigator 2.0
The Navigator 2.0 API adds new classes to the framework in order to make the app’s screens a function of the app state and to provide the ability to parse routes from the underlying platform (like web URLs). Here’s an overview of what’s new:
Page
— an immutable object used to set the navigator’s history stack.
const Page({
this.key,
super.name,
super.arguments,
this.restorationId,
});
Router
— configures the list of pages to be displayed by the Navigator. Usually this list of pages changes based on the underlying platform, or on the state of the app changing.
const Router({
super.key,
this.routeInformationProvider,
this.routeInformationParser,
required this.routerDelegate,
this.backButtonDispatcher,
this.restorationScopeId,
}) : assert(
routeInformationProvider == null || routeInformationParser != null,
'A routeInformationParser must be provided when a routeInformationProvider is specified.',
);
RouteInformationParser
, which takes theRouteInformation
fromRouteInformationProvider
and parses it into a user-defined data type.RouterDelegate
— defines app-specific behavior of how theRouter
learns about changes in app state and how it responds to them. Its job is to listen to theRouteInformationParser
and the app state and build theNavigator
with the current list ofPages
.BackButtonDispatcher
— reports back button presses to theRouter
.
Here’s an example of how these pieces interact:
- When the platform emits a new route (for example, “books/2”) , the
RouteInformationParser
converts it into an abstract data typeT
that you define in your app (for example, a class calledBooksRoutePath
). RouterDelegate
’ssetNewRoutePath
method is called with this data type, and must update the application state to reflect the change (for example, by setting theselectedBookId
) and callnotifyListeners.
- When
notifyListeners
is called, it tells theRouter
to rebuild theRouterDelegate
(using itsbuild()
method) RouterDelegate.build()
returns a newNavigator
, whose pages now reflect the change to the app state (for example, theselectedBookId
).
Imagine you have a magical platform that can take you to different places. Each place is called a route. For example, there’s a route called “books” that takes you to a library, and within that route, there are different books you can visit. Now, let’s say you want to go to the second book in the library.
First, the platform tells everyone that there’s a new route available called “books/2”, which means the second book in the library. This information is given to a special translator called RouteInformationParser. The translator understands this new route and converts it into a special type of information that we can use.
Next, there is a guide called RouterDelegate who knows how to handle these routes. When the translator gives it the information about the new route (“books/2”), the guide’s job is to update the state of our app to show that we have selected the second book. It also tells everyone that the state has changed by calling notifyListeners.
When notifyListeners is called, it’s like sending a message to the Router, which is like a supervisor. The Router tells the guide, “Hey, something has changed! Please rebuild yourself.” So the guide rebuilds itself by using its build() method.
Now, after the guide has rebuilt itself, it creates a new Navigator. Think of the Navigator as a map that shows all the pages of our app. This map is updated based on the changes in the app state. For example, the selected book is now the second book, so the Navigator updates its pages to reflect that change. Now, when you look at the map (Navigator), you can see that the second book is selected.
That’s how these different pieces work together to handle new routes and update the app accordingly. It’s like a team of magical helpers that make sure we go to the right place and see the right things in our app.