npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

retrack

v1.2.2

Published

never hardcode paths to redux state again!

Downloads

798

Readme

Retrack

A simple Redux library that tracks the way your reducers are combined in order to:

  • dynamically create a selector for each reducer.
  • namespace your action types based on the position of corresponding reducer in the state tree.

that's it! two of the most known issues with scaling your redux apps is solved now. Enjoy!

Installation

$ yarn add retrack

or

$ npm install --save retrack

Import

Retrack's public API consists of these functions:

// ES2015 Modules
import {
  combineTrackReducers,
  getSelector,
  namespaceReducerActions,
  setNamespacingFunction
} from 'retrack'

// CommonJS
const { ... } = require('retrack')

Public API

combineTrackReducers(reducers)

You should use this function instead of redux's default combineReducers everywhere in your project so Retrack knows the shape of your state tree in order to give you the functionality that you're looking for. It internally calls combineReducers from your own version of redux and returns the same result, except that it also does some extra stuff for tracking. note that reducers must be an object with string keys and your reducers as values.

getSelector(reducer)

You can use getSelector on any of your reducers (which of course you passed to combineTrackReducers at some point) to get a selector function. This selector maps the giant redux state of your application into the state value that the corresponding reducer controls.

namespaceReducerActions(reducer, actionTypes)

By calling this function you tell Retrack to namespace your actionTypes based on the position of reducer in the state tree. if you want this feature you MUST use the pattern in the example below, which is to pass an actionTypes object, a key value pair that values are string values you wish to use as action type and use actionTypes.ACTION_TYPE whenever you want to refer to an action type (in reducer or action creator). hope the example below clarifies more.

setNamespacingFunction(customFunction)

You can customize the logic of namespacing your action types by passing your customFunction here. Your function will get an array of strings and should return your custom action type. The array of strings given to your function will be the strings indicating the path of reducer in the state tree as well as the action type itself as the last value. If you don't call this function, (strArr) => strArr.join('/') will be used by default.

Example

import { createStore } from 'redux'
import {
  combineTrackReducers,
  getSelector,
  namespaceReducerActions,
  setNamespacingFunction
} from 'retrack'

// define your reducers and setup store
const counterActionTypes = {
  INCREMENT: 'INCREMENT',
  DECREMENT: 'DECREMENT'
}
function counter(state = 0, action) {
  switch (action.type) {
    case counterActionTypes.INCREMENT:
      return state + 1
    case counterActionTypes.DECREMENT:
      return state - 1
    default:
      return state
  }
}
namespaceReducerActions(counter, counterActionTypes)

const nameActionTypes = { SET_NAME: 'SET_NAME' }
function name(state = 'default name', action) {
  if (action.type === nameActionTypes.SET_NAME) return action.payload.name
  return state
}
namespaceReducerActions(name, nameActionTypes)

const firstApp = combineTrackReducers({
  counter: counter,
  name: name
})

function secondApp(state = 'under construction', action) {
  return state
}

const store = createStore(
  combineTrackReducers({
    firstAppName: firstApp,
    secondAppName: secondApp
  })
)

// later when you want to get values from state
const state = store.getState()

const counterSelector = getSelector(counter) /* equivalent to `(state) => state.firstAppName.counter` */
console.log(counterSelector(state))            // 0

const nameSelector = getSelector(name) /* equivalent to `(state) => state.firstAppName.name` */
console.log(nameSelector(state))               // default name

console.log(getSelector(firstApp)(state))      // {counter: 0, name: "default name"}

console.log(getSelector(secondApp)(state))     // under construction

// ...

console.log(counterActionTypes.INCREMENT)      // firstAppName/counter/INCREMENT
store.dispatch({ type: counterActionTypes.INCREMENT })
console.log(counterSelector(store.getState())) // 1

console.log(nameActionTypes.SET_NAME)          // firstAppName/name/SET_NAME
store.dispatch({ type: nameActionTypes.SET_NAME, payload: { name: 'another name' } })
console.log(nameSelector(store.getState()))    // another name

// you should probably use this when you setup your store, It's here just for the example
setNamespacingFunction((strArr) => strArr.join('-> '))
console.log(nameActionTypes.SET_NAME)          // firstAppName-> name-> SET_NAME

As you have noticed action types like counterAction.INCREMENT are no longer the strings you passed to namespaceReducerActions at first. Retrack behind the scene overrides the action names to be getter functions that produce namespaced action name dynamically based on your state tree. And that's why you must stick to this pattern. If you hardcode an action name by mistake, or capture the value at some point during setup and reuse that value, you'll lose this dynamically namespacing feature.