Giter Club home page Giter Club logo

csells / go_router Goto Github PK

View Code? Open in Web Editor NEW
441.0 11.0 96.0 16.24 MB

The purpose of the go_router for Flutter is to use declarative routes to reduce complexity, regardless of the platform you're targeting (mobile, web, desktop), handling deep linking from Android, iOS and the web while still allowing an easy-to-use developer experience.

Home Page: https://gorouter.dev

Dart 96.28% HTML 1.48% Swift 0.61% Ruby 1.07% Kotlin 0.05% Objective-C 0.02% Shell 0.49%
flutter router navigation routing

go_router's Introduction

go_router is now published and maintained by the Flutter team

As of the 3.0.2 release, the go_router package is published by the Flutter team and maintained by Flutter engineering in the flutter/packages repository.

Existing go_router issues have been moved to the flutter issues list and new go_router-related issues should be filed there.

The docs on gorouter.dev will also be moving to docs.flutter.dev over time.

This repo has been archived and is read-only.

Pub Version Test codecov License

Welcome to go_router!

The purpose of the go_router package is to use declarative routes to reduce complexity, regardless of the platform you're targeting (mobile, web, desktop), handle deep and dynamic linking from Android, iOS and the web, along with a number of other navigation-related scenarios, while still (hopefully) providing an easy-to-use developer experience.

You can get started with go_router with code as simple as this:

class App extends StatelessWidget {
  App({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) => MaterialApp.router(
        routeInformationParser: _router.routeInformationParser,
        routerDelegate: _router.routerDelegate,
        title: 'GoRouter Example',
      );

  final _router = GoRouter(
    routes: [
      GoRoute(
        path: '/',
        builder: (context, state) => const Page1Screen(),
      ),
      GoRoute(
        path: '/page2',
        builder: (context, state) => const Page2Screen(),
      ),
    ],
  );
}

class Page1Screen extends StatelessWidget {...}

class Page2Screen extends StatelessWidget {...}

But go_router can do oh so much more!

See gorouter.dev for go_router docs & samples

go_router's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go_router's Issues

README fix

"policy using the MaterialApp.router constructor" => "policy using the MaterialApp constructor"

can't seem to have an initial page that's not a home page unless there's also a home page

e.g. the following doesn't work:

late final _router = GoRouter(
  routes: _routesBuilder,
  error: _errorBuilder,
  initialLocation: '/page1', <-- set initial page
  redirect: (context, state) => state.pattern == '/' ? '/page1' : null, <-- redirect home page to initial page
);

List<GoRoute> _routesBuilder(BuildContext context, String location) => [
  GoRoute(
    pattern: '/page1',
    builder: (context, state) => const MaterialPage<Page1Page>(
      key: ValueKey('Page1Page'),
      child: Page1Page(),
    ),
  ),
  GoRoute(
    pattern: '/page2',
    builder: (context, state) => const MaterialPage<Page2Page>(
      key: ValueKey('Page2Page'),
      child: Page2Page(),
    ),
  ),
];

it goes to the error page instead.

add a key property to GoRouteState

this enables me to simplify my MaterialPage building, e.g. from this

return MaterialPage<PersonPage>(
  key: ValueKey(person), // key from value
  child: PersonPage(family: family, person: person),
);

return MaterialPage<FamiliesPage>(
  key: const ValueKey('FamiliesPage'), // key from constant
  child: FamiliesPage(families: Families.data),
);

to this:

return MaterialPage<PersonPage>(
  key: state.key, // key from sub-location, e.g. /family/f2/person/f1
  child: PersonPage(family: family, person: person),
);

return MaterialPage<FamiliesPage>(
  key: state.key, // key from sub-location, e.g. /
  child: FamiliesPage(families: Families.data),
);

This works because we already have a value the changes based on the variability needed for the key, i.e. the sub-location of the current page, which is just the pattern expanded with the current set of params.

multi-page routing: return multiple pages for a single route pattern

would it be useful to add support for shorter locations that result in multiple pages for a single route. For example, /person/:pid could end up mapping to three pages (families, family and person) but will only match two routes
(families and person). The mapping to person requires two pages to be returned (family and person).

[Question] Possibility to pass complex arguments to routes

Hi ๐Ÿ‘‹๐Ÿผ ! Firstly I'd like to thank you for this package ๐Ÿ’™

Problem

I have a use case where I need to pass complex objects as arguments to some pages (instead of an ID). I haven't seen anything related on the docs so I asked myself if this is possible with the current package implementation.

As far as I understand the only way to pass arguments to routes with the package paradigm is via query parameters, which has a limit between 1024 and 2048 characters; which may cause me trouble in the future...

  • Do you think is it possible to solve with the package current implementation?
  • If not, is it posible to add this feature in the future?
  • Or maybe this problem can't be solved via this routing paradigm?

Is there any way to do something similar to pushReplacement?

In my App I need to a do a Push within the same Path multiple times, so can't use "context.go" because it doesn't go through the initState. And doing a "context.push) to the same Route it's bad for performance and for example, when there are Controllers for ListViews, it starts showing errors because the same Controller is attached to multiple views in the Stack. Couldn't find anything in the documentation about this. Thanks!

Query Params vs URL Params

I find it a bit confusing that both are mapped to state.params. Is there a reason for that? Would you consider actually adding state.queryParams for query parameters?

API docs needed

Undocumented (24):

  pageKey: go_router.dart:44:3
  matchPatternAsPrefix: go_router.dart:113:3
  extractPatternParams: go_router.dart:114:3
  go: go_router.dart:181:3
  goNamed: go_router.dart:182:3
  location: go_router_impl.dart:134:3
  matches: go_router_impl.dart:137:3
  navigatorKey: go_router_impl.dart:146:3
  currentConfiguration: go_router_impl.dart:149:3
  go: go_router_impl.dart:110:3
  goNamed: go_router_impl.dart:116:3
  refresh: go_router_impl.dart:128:3
  dispose: go_router_impl.dart:140:3
  build: go_router_impl.dart:155:3
  setInitialRoutePath: go_router_impl.dart:162:3
  setNewRoutePath: go_router_impl.dart:178:3
  getNameRouteMatch: go_router_impl.dart:421:3
  safeNotifyListeners: go_router_impl.dart:594:3
  parseRouteInformation: go_router_impl.dart:613:3
  restoreRouteInformation: go_router_impl.dart:620:3
  updateShouldNotify: go_router_impl.dart:639:3
  GoRouteMatch: go_router_impl.dart:643:1
  match: go_router_impl.dart:660:3
  matchNamed: go_router_impl.dart:686:3

Navigational Observers

Hello,

Thanks for all the effort here. I have a question related to using of navigational observers. How can we use them with go_router?
For example third party apps like FirebaseAnalyticsObserver that need to be passed to this router.

Best,
Hari

Allow sub route path to be absolute path

Let's say I want the route paths to be like '/login and /sign-up. And I want them to be stacked so that if users first come in /login and go to /sign-up and then try to go back to /login again, it will allow them to easily go back by pressing the back button on Android or swipe right on iOS.

But the current implementation seems forces me to set sub route paths to not start with /. It forces me the /sign-up path to be /login/sign-up.

Scroll position is reset when returning from navigation

I have a tab screen using AutomaticKeepAliveClientMixin that has a listview of many items. When a user clicks one of those items, I do a pushNamed() to get to the detail view of that item, and the appbar provides the back button to pop the navigation stack. When the navigation stack gets popped back to the original listview tab, the scroll position goes back to the top.

I do no this issue when using the traditional router. Only with go_router.

This issue might be related to #44 .

Thanks!

safe way to notify listeners?

is this necessary?

  // HACK: this is a hack to fix the following error:
  // The following assertion was thrown while dispatching notifications for
  // GoRouterDelegate: setState() or markNeedsBuild() called during build.
  void safeNotifyListeners() {
    final instance = WidgetsBinding.instance;
    if (instance != null)
      instance.addPostFrameCallback((_) => notifyListeners());
    else
      notifyListeners();
  }

It stops the run-time errors and works in the tests...

fix support for Link widget and context.go() on books sample's Settings page

when running the Books sample in the browser:

  1. going to /book/0 should end up at /books/all/0 (with /books/all shown when the user presses Back on the AppBar)
  2. that page is shown briefly but then the app goes to /books/all immediately for some reason
  3. going to either /book/0 OR /books/all/0 directly from the browser's address bar works just fine

allow push() as well as go()

should an app be able to support pushing onto the stack as well as specifying the entire stack with each location?

make redirection reusable

right now, you have to implement the same code over and over. this will require another callback.

document go_router + AutomaticKeepAliveClientMixin to keep ListView scroll position

Shawn: "If you stick an AutomaticKeepAliveClientMixin on any of the top-level tabs, then they retain their state between tabs and you get the full "nested navigation + persistent tabs" that many folks are looking for. Just had to make FamilyView stateful, and add that mixin to the state, and the ListView remembers it's scroll position between routes! The entire widget state is retained. Like I can add a counter btn to each view, or a textfield, totally retains state between tabs."

set the URL strategy as a property on the GoRouter ctor

e.g. instead of this:

void main() {
  GoRouter.setUrlStrategy(UrlStrategy.path);
  runApp(MyApp());
}

can I allow this?

class MyApp extends StatelessWidget {
  final _router = GoRouter(strategy: UrlStrategy.path, ...);
  ...
}

the question is whether the router is created soon enough to allow for this.

test coverage

Can't be a Flutter Favorite without good test coverage!

  • unit testing
  • widget testing

Redirect not working correctly on web

I am having an issue with the redirect not working correctly (or maybe I am using it wrong?). In the code below, I simply force a redirect to the "/login" screen every time. However, I get the error page.

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  MyApp({Key? key}) : super(key: key);
  late final _router = GoRouter(
    routes: [
      GoRoute(
        path: "/",
        name: "home",
        pageBuilder: (context, state) => MaterialPage<void>(
          key: state.pageKey,
          child: const Scaffold(
            body: Text("Home page"),
          ),
        ),
      ),
      GoRoute(
        path: "/login",
        name: "login",
        pageBuilder: (context, state) => MaterialPage<void>(
          key: state.pageKey,
          child: const Scaffold(
            body: Text("Login page"),
          ),
        ),
      ),
    ],
    errorPageBuilder: (context, state) => MaterialPage<void>(
      key: state.pageKey,
      child: const Scaffold(
        body: Text("Page not found"),
      ),
    ),
    redirect: (state) {
      return "/login";
    },
  );

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      routeInformationParser: _router.routeInformationParser,
      routerDelegate: _router.routerDelegate,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
    );
  }
}

add a GoRouter.builder ctor

it should take two functions:

  1. a navigate function that does the redirection and builds up the stack of page builders
  2. a builder function that creates the Navigator with the stack of pages from the page builders
GoRouter.builder(
  String Function(String location) navigate, // returns whatever loc redirection lands on
  Widget Function(BuildContext context, String location) builder, // builds the Navigator
)

// the delegate implementation becomes easy now
void go(String location) {
  _loc = this.navigate(location);
  notifyListeners(); // calls build()
}

Widget build(BuildContext context) => this.builder(context);

That's what the real API is for Nav2 and on top of that can be built the declarative routing solution that's in place now.

enable relative routing

e.g. if the current location in /, then routing to foo will route to /foo.

otoh if the current location in /bar, then routing to foo will route to /bar/foo.

otgh routing to /anything will disregard the current location.

use nested instead of flat routing to match nested routes

e.g. /family/f2/person/p1 current creates a stack like so

GoRoute(pattern: '/family/:fid', builder: (context, state) => FamilyPage(state.args['fid'])
GoRoute(pattern: '/family/:fid/person/:pid', builder: (context, state) => PersonPage(state.args['pid])

and creates the stack for everything that matches. This confuses people. It would be easier to understand if a single route were matched and sub-routes were matched explicitly:

GoRoute(
  pattern: '/family/:fid',
  builder: (context, state) => FamilyPage(state.args['fid']),
  routes: [
    GoRoute(pattern: 'person/:pid', builder: (context, state) => PersonPage(state.args['pid])
  ]
)

This style of sub-routing also lends itself to nested navigation as well.

Does the constructed navigation stack overrides the current stack?

"an entire stack of pages can be constructed from the route name alone"

If a user has been navigating on these routes A > B > C (navigation history contains A, B, and C) and types family/f1 in the browser, does it override the A, B, C history?

How to sync both constructed and real navigation history?

error when doing redirection

Launching lib/redirection.dart on Chrome in debug mode...
This app is linked to the debug service: ws://127.0.0.1:56813/9105vGEYbCI%3D/ws
Debug service listening on ws://127.0.0.1:56813/9105vGEYbCI=/ws
๐Ÿ’ช Running with sound null safety ๐Ÿ’ช
Connecting to VM Service at ws://127.0.0.1:56813/9105vGEYbCI=/ws

โ•โ•โ•โ•โ•โ•โ•โ• Exception caught by widget library โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
The following assertion was thrown:
The Navigator.pages must not be empty to use the Navigator.pages API

When the exception was thrown, this was the stack
dart-sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart 909:28 get current
packages/flutter/src/widgets/navigator.dart 3366:33
packages/flutter/src/widgets/navigator.dart 3382:14 initState
packages/flutter/src/widgets/framework.dart 4711:57 [_firstBuild]
packages/flutter/src/widgets/framework.dart 4548:5 mount
...
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

โ•โ•โ•โ•โ•โ•โ•โ• Exception caught by widgets library โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
Navigator.onGenerateRoute was null, but the route named "/" was referenced.
The relevant error-causing widget was
InheritedGoRouter
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

โ•โ•โ•โ•โ•โ•โ•โ• Exception caught by widget library โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
The Navigator.pages must not be empty to use the Navigator.pages API
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

โ•โ•โ•โ•โ•โ•โ•โ• Exception caught by widgets library โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
Navigator.onGenerateRoute was null, but the route named "/" was referenced.
The relevant error-causing widget was
InheritedGoRouter
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

โ•โ•โ•โ•โ•โ•โ•โ• Exception caught by widget library โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
A HeroController can not be shared by multiple Navigators. The Navigators that share the same HeroController are:
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

โ•โ•โ•โ•โ•โ•โ•โ• Exception caught by widget library โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
A HeroController can not be shared by multiple Navigators. The Navigators that share the same HeroController are:
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.