kitze/mobx-router

Interceptable Link

Opened this issue · 2 comments

I use the Link component and it's awesome. But there's no way I can intercept that click.
In particular, depending on some programmatic logic I'd like to do some things in the onClick that may or may not cancel the click. For example:

<Link
    view={views.podcast}
     params={{id: podcast.id, slug: podcast.slug}}
     store={store}

     // pseudo code!
      onClick={e => {
          if (someCondition) {
            store.app.something = 'foo'
            return false
          } 
      }}
     >
   Click Here
</Link>

It's always a bit weird to have multiple onClick events because it's confusing what the order is supposed to be.

Here's a hack I wrote for my own needs. This works well:

export const InterceptableLink = ({
  view,
  className,
  params = {},
  queryParams = {},
  store = {},
  refresh = false,
  style = {},
  children,
  title = children,
  router = store.router,
  onClick = null,   // THIS IS NEW
}) => {
  if (!router) {
    return console.error('The router prop must be defined for a Link component to work!')
  }
  return (<a
      style={style}
      className={className}
      onClick={e => {

        // THESE LINES ARE NEW
        if (onClick && onClick(e) === false) {
          e.preventDefault();
          return;
        }
        // END NEW LINES

        const middleClick = e.which === 2;
        const cmdOrCtrl = (e.metaKey || e.ctrlKey);
        const openinNewTab = middleClick || cmdOrCtrl;
        const shouldNavigateManually = refresh || openinNewTab || cmdOrCtrl;

        if (!shouldNavigateManually) {
          e.preventDefault();
          router.goTo(view, params, store, queryParams);
        }
      }}
      href={view.replaceUrlParams(params, queryParams)}>
      {title}
    </a>
  )
}

Do you think that's a good idea? If so, I can clean it up in the form of a PR.

By the way, here's why I think it's an awesome idea.
I have a tabular page. It does an AJAX query (e.g. /api/items/?page=1). If you click on one of them, it goes to the "perma page" for that item. Then, to get the data it does an AJAX query again (e.g. /api/items?id=1234 and something like...

.then(result => {
    store.app.item = result.items[0]
})

(It also loads other stuff that isn't displayed in the tabular page)

So by intercepting the click, from the tabular page, I can do this:

          <InterceptableLink
            view={views.podcast}
            params={{id: podcast.id, slug: podcast.slug}}
            store={store}
            onClick={e => {
              store.app.podcast = podcast  // <--- here lies the magic!
            }}
          >
            <img src={imageURL} role="presentation" className="rounded"/>
          </InterceptableLink>

That means that when the perma page loads, the data will already have been put in the store and thus it loads instantaneous!

kitze commented

Ah, this looks really interesting. Will take a stab at it soon! 🙌