flutter / uxr

UXR work for Flutter
BSD 3-Clause "New" or "Revised" License
227 stars 28 forks source link

Provide common state to nested routes #72

Closed oodavid closed 2 years ago

oodavid commented 3 years ago

Our app often forwards data to "child" routes.

We'd prefer child routes to inherit data from parent routes.

Example

Here we have an app to view and comment on user's photos:

/users/123
/users/123/photos
/users/123/photos/456
/users/123/photos/456/comments

On /users/123 we access user = User(123) from the database and Provide it to the widget tree to render their profile.

On the "child" views we also want access to user. Currently we pass this data as props to the new screens. This works well, but starts to feel a little boilerplatey once you get quite deep.

You can imagine the data that /users/123/photos/456/comments/678/likes may want access to.

InMatrix commented 2 years ago

Cc a few package authors for their consideration / responses: @lulupointu @slovnicki @Milad-Akarie @tomgilder.

lulupointu commented 2 years ago

What you want to do is more linked with state management than routing. Some routing packages have limited state management capabilities but I think the easiest way would be to use a real state management library (read: provider, bloc, etc.).

Milad-Akarie commented 2 years ago

In auto_route you have easy access to inherited path params.

context.routeData.inhertiedPathParams;
oodavid commented 2 years ago

@lulupointu - What you want to do is more linked with state management than routing. Some routing packages have limited state management capabilities but I think the easiest way would be to use a real state management library (read: provider, bloc, etc.).

We use Provider, but context.read and context.watch are limited to the current Route, thus cannot access data on the previous Routes. That's certainly a limitation of Provider (and InheritedWidget). Maybe I'm missing some fundamental paradigm?

lulupointu commented 2 years ago

We use Provider, but context.read and context.watch are limited to the current Route, thus cannot access data on the previous Routes. That's certainly a limitation of Provider (and InheritedWidget). Maybe I'm missing some fundamental paradigm?

It depends where you put your provider with regard to how your routes are formed.

In VRouter you can use VNester to do dependencies injections in multiple routes.

Here is an example to illustrate that ```dart // GOOD VRouter( routes: [ VNester.builder( path: '/user/:id', widgetBuilder: (_, state, child) => Provider( create: (_) => User(state.pathParameters['id']), child: child, ), nestedRoutes: [ VWidget( path: null, // Match parent widget: UserScreen(), stackedRoutes: [ VWidget(path: 'photos', widget: PhotosScreen()), // DOES have access to the provider ], ), ], ), ], ); // BAD VRouter( routes: [ VWidget( path: '/user/:id', // Match parent widget: Provider( create: (_) => User(state.pathParameters['id']), child: UserScreen(), ), stackedRoutes: [ VWidget(path: 'photos', widget: PhotosScreen()), // Does NOT have access to the provider ], ), ], ); ```

This is using VRouter but the idea is that it should be possible with any packages, the challenge being to know where to inject the provider

xuanswe commented 2 years ago

We use Provider, but context.read and context.watch are limited to the current Route, thus cannot access data on the previous Routes. That's certainly a limitation of Provider (and InheritedWidget). Maybe I'm missing some fundamental paradigm?

@oodavid I think the best approach is that, you reorganize your widget tree to provide user state in the upper node of all dependent children. Not only in the case of routing, in any similar case, we should always try to do it.

Sometime, following this approach is more difficult if routing packages don't use the state as the single source of truth. In this case, you should compare 2 options below and choose the better one for your case:

InMatrix commented 2 years ago

Closing this issue since it's obsolete.