How-To: URL State Sharing / Deep Linking using Microcosm

Mike Ackerman, Former Senior Developer

Article Categories: #Code, #Front-end Engineering

Posted on

Using a Microcosm Effect, learn how to populate and share your app's state via URL query parameters.

How many times have you received a link to a website from a loved one, you visit it, and the site doesn't know how to load the proper data? I'm looking at you airline sites...

We should be nice to our users and make it so our application can share search state with another user by simply sharing a URL.

I'm going to show you one solution that I recently used while working on a client-side-app (lots of JavaScript) using Microcosm.


  1. Trigger the Microcosm action to update the app state (and URL query)
push(storeQuery, queryData)

2. Create and add a Microcosm Effect (which will do the listening):

setup(repo) { repo.addEffect(UrlPersistenceEffect) }

Note: I add the Effect in a Presenter's setup method because setup has access to repo and as you'll see later I only want this behavior in a certain part of my app. Otherwise, I'd recommend adding the Effect to your main app Repo initialization.

The Effect:

import { merge } from 'microcosm'
import qs from 'qs'
import {
  windowHashAsObject
} from 'lib/url'

class UrlPersistenceEffect { 
  register() {
    return {
      [storeQuery] : this.patchQuery
    }
  }
  
  patchQuery(queryData) {
    let queryHash = windowHashAsObject()
    queryHash = merge(queryHash, queryData)
    window.location.hash = qs.stringify(queryHash)
  }
}

// lib/url.js
import qs from 'qs'

export function windowHashAsObject() {
  let windowHash = window.location.hash.substring(1) // remove the '#'
  return qs.parse(windowHash)
}

3. (Optional): If you also want to store the search state in your application's state, register this action in a regular 'ole domain:

export default const SearchDomain { 
  ... 
  register() {
    return {
      [storeQuery] : this.storeQuery
    }
  }
  ...
}

4. (BONUS!!! 🎉) If you want the URL search state query to "come and go" when the UI state is in a certain mode (like I did), in your Effect do:

setup(repo) {
  this.populateUrlHashFromAppState(repo)
}

teardown(repo) {
  history.pushState("", document.title, window.location.pathname + window.location.search);
}

populateUrlHashFromAppState(repo) {
  let { queryData } = repo.state.search

  this.patchQuery(repo, queryData)
}

5. To populate the user who received the URL's app state when visiting the shared link, in your Effect do:

setup( {
  if (urlHasHashObject()) {
    this.populateAppStateFromUrlHash(repo)
  } else {
    this.populateUrlHashFromAppState(repo)
  }
}

populateAppStateFromUrlHash(repo) {
  let queryData = windowHashAsObject()
  repo.push(storeQuery, queryData)
}

This could have been done using only react-router's history or location and react, but we would lose the benefit of having this feature encapsulated in a single file, a Microcosm Effect.

Do you have an alternate solution or appreciate this one? If so, please leave a comment below!

Related Articles