navi icon indicating copy to clipboard operation
navi copied to clipboard

How to combing views with shared component and other views

Open linlycode opened this issue 6 years ago • 4 comments

Some of my views share a navigation bar and some doesn't, how do I combine them?

For example, suppose my app have 3 pages, "home", "products" and "about", "home" and "products" have a shared navigation bar, but "about" doesn't.

From the docs I know that I can share component with withView:

withView((
    <>
      <NavBar />
      <View />
    </>
  ),
  mount({
    '/': route({
      title: 'Home',
      view: <Home />,
    }),
    '/products': route({
      title: 'Products',
      view: <Products />,
    }),
  })
)

But it's not clear how to add other routes that doesn't need the shared component.

I've tried to use compose, but it seemed mount can't be "composed"? I got 404 for "/about" with this code:

const shared = withView((
    <>
      <NavBar />
      <View />
    </>
  ),
  mount({
    '/': route({
      title: 'Home',
      view: <Home />,
    }),
    '/products': route({
      title: 'Products',
      view: <Products />,
    }),
  })
)

compose(
  shared,
  mount({
    '/about': route({
      title: 'About',
      view: <About />,
    }),
  })
)

I've looked at the source code of frontarm.com/navi/, but I didn't find routes for "/learn" and "/articles" mentioned here, so I guess I missed something.

So how do I do it correctly?

linlycode avatar Jul 19 '19 04:07 linlycode

The way to do this is with wildcards on the mount(). This lets you direct the mount to fall through to another matcher if it fails to match, which can then be wrapped with a withView():

mount({
  '/about': lazy(() => import('./about')),
  '*': compose(
    withView(
      <AppLayout>
        <View />
      </AppLayout>
    ),
    mount({
      '/home': lazy(() => import('./home')),
      '/products': lazy(() => import('./products')),
    })
  )
})

jamesknelson avatar Jul 19 '19 04:07 jamesknelson

The way to do this is with wildcards on the mount(). This lets you direct the mount to fall through to another matcher if it fails to match, which can then be wrapped with a withView():

mount({
  '/about': lazy(() => import('./about')),
  '*': compose(
    withView(
      <AppLayout>
        <View />
      </AppLayout>
    ),
    mount({
      '/home': lazy(() => import('./home')),
      '/products': lazy(() => import('./products')),
    })
  )
})

This solves the problem, but what if I have another page that shares a component with "/about" ?

linlycode avatar Jul 19 '19 05:07 linlycode

That's a good question. I'm not sure I've got a great answer, but given that withView just returns a function, one possibility would be to create a layout, and apply it to each route individually:

const withMainLayout = (route) => compose(withView(...), route)
const withSecondaryLayout = (route) => compose(withView(...), route)

mount({
  '/about': withSecondaryLayout(route(...)),

  '/home': withMainLayout(route(...)),
  '/products': withMainLayout(route(...)),
})

I've looked into making it so you can do compose(mount(), mount()) before, but from memory there was some issue that prevented it -- I think to it was related to the static build process. I'd definitely be open to PRs to make this easier though if it can be made to work with the build tools.

jamesknelson avatar Jul 19 '19 05:07 jamesknelson

That's a good question. I'm not sure I've got a great answer, but given that withView just returns a function, one possibility would be to create a layout, and apply it to each route individually:

const withMainLayout = (route) => compose(withView(...), route)
const withSecondaryLayout = (route) => compose(withView(...), route)

mount({
  '/about': withSecondaryLayout(route(...)),

  '/home': withMainLayout(route(...)),
  '/products': withMainLayout(route(...)),
})

I've looked into making it so you can do compose(mount(), mount()) before, but from memory there was some issue that prevented it -- I think to it was related to the static build process. I'd definitely be open to PRs to make this easier though if it can be made to work with the build tools.

Thanks for your support! I've thought of the "with" method, but composing mount is more natural and concise, I'd like to find out how to do it when I have time.

linlycode avatar Jul 19 '19 06:07 linlycode