uxr icon indicating copy to clipboard operation
uxr copied to clipboard

Provide common state to nested routes

Open oodavid opened this issue 2 years ago • 6 comments

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.

oodavid avatar Sep 03 '21 07:09 oodavid

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

InMatrix avatar Oct 21 '21 21:10 InMatrix

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.).

lulupointu avatar Oct 21 '21 22:10 lulupointu

In auto_route you have easy access to inherited path params.

context.routeData.inhertiedPathParams;

Milad-Akarie avatar Oct 21 '21 22:10 Milad-Akarie

@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?

oodavid avatar Oct 26 '21 15:10 oodavid

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
// 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

lulupointu avatar Oct 26 '21 15:10 lulupointu

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:

  • alternative solutions of your selected routing package
  • extract the state to outside of the widget tree (ex. a bloc) and query it anytime/anywhere you want.

xuanswe avatar Oct 28 '21 15:10 xuanswe

Closing this issue since it's obsolete.

InMatrix avatar Aug 15 '22 20:08 InMatrix