Skip to content

Instantly share code, notes, and snippets.

@iammerrick
Created October 18, 2016 20:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iammerrick/0e0de77f399ffce552af459ab52b0735 to your computer and use it in GitHub Desktop.
Save iammerrick/0e0de77f399ffce552af459ab52b0735 to your computer and use it in GitHub Desktop.

Tree

// State Tree itself should be normalized and lean towards flat (sort of like a traditional relational database)
//
{
  // Route Parameters
  params: {
    pageId: 1,
  },
  // Card Reducer
  cards: {
    1: {
      ...
    },
    2: {
      ...
    }
  },
  // Page Reducer
  pages: {
    1: {
      title: 'Some Page',
      cards: new Set(1, 2) // not JSON but important to leverage set for guaranteed uniqueness

    }
  }
}

Selectors

You then use what is called a selector to render a page, or component, etc. The selector can be what you need for the whole UI or just a given component.

const selectCurrentPage = (state) => {
  const page = state.pages[state.params.pageId];
  return {
    ...page,
    cards: page.cards.map((cardId) => state.cards[cardId])
  }
};

To create efficient selectors you can use memoization, see: https://github.com/reactjs/reselect (not coupled to React)

// In this case the work of merging & mapping would be done once, no matter how many re-renders you caused. Truth is though in this case we are just passing around references which is exceptionally fast.
// This gives you a place to do efficient computations & derived data without a messing up your state tree.
// Important to use a memo with a cache size of 1
const selectCurrentPage = createSelector(
  selectPageByCurrentId,
  (page) => ({
    ...page,
    cards: page.cards.map((cardId) => state.cards[cardId])
  })
);

Something really dope about this pattern is that we return the same reference if nothing has changed and a new reference if something has changed. This means our UI framework can use reference semantics to know when to re-render instead of deep comparisons.

So instead of deepEqual(one, two) our UI tool can say one !== two and know when to re-render. One of the many benefits of immutability.

Action Creators

Actions creators the things that provide actions for the tree can be effecient by using the tree's existing state, this is useful to avoid duplicate requests/work if something already exists in the tree

const getPage = (id) => ((dispatch, getState) => {
  if (selectPageByCurrentId() !== null) return null; // We can short circuit since we have this data, we can be smart about how we do this to based on semantics around the data itself.
  fetch(`/page/${id}`)
    .then((response) => {
      dispatch({
        type: 'PAGE_LOAD',
        paylod: response.json()
      });
    }):
})
@statianzo
Copy link

Your reselect selector body has a reference to state in it. Add a dependency to (state) => state.cards to the selector.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment