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 🙏

© 2026 – Pkg Stats / Ryan Hefner

offramp

v0.0.4

Published

A routing library for React that keeps your router's state in sync with application state.

Readme

Offramp

Offramp is a React library that provides simple routing for your single page applications.

Features

  • Synchronized routing state with application state
  • Decoupled state from UI
  • Routes support hooks such as beforeEnter, onEnter, beforeExit, and onExit
  • Async-rendering & data-fetching before component render

Quick Start

To get started, yarn add offramp.

MobX

import React from 'react';
import { render } from 'react-dom';
import { RouterStore, Router, Route } from 'offramp/mobx';
import { Provider } from 'mobx-react';

// import your mobx stores and place them in stores object
// create router property with a value of the routerStore
const routerStore = new RouterStore();

const stores = {
	// your stores here..
	router: routerStore
};

Redux

import React from 'react';
import { render } from 'react-dom';
import { routerReducer, Router, Route } from 'offramp/redux';
import { Provider } from 'react-redux'

// import your reducers and pass them in with the routerReducer
const stores = createStore(combineReducers({
  // ...reducers
  router: routerReducer
});

React

import React from 'react';
import { render } from 'react-dom';
import { Router, Route } from 'offramp';

Once all the correct dependencies are imported, just define your routes

// import all your components for your routes
import Main from './components/Main';
import Home from './components/Home';
import About from './components/About';
import UsersPage from './components/UsersPage';
import NotFound from './components/NotFound';

// if you're just using React, remove the Provider
render(
  <Provider store={stores}>
    <Router>
      <Route path='/' component={Main}>
        <Route index component={Home} />
        <Route path='/about' component={About} />
        <Route path='/users' component={UsersPage} />
      </Route>
      <Route path='*' component={NotFound} />
    </Router>
  </Provider>,
  document.getElementById('root')
);

Getting Started

Installation

Using npm:

npm install offramp --save

or yarn:

yarn add offramp

Using Offramp

To get started, create your index.js file and import what you need depending on which state management library you are using:

import React from 'react';
import { render } from 'react-dom';
import { routerStore, Router, Route } from 'offramp/mobx'; // mobx
import { routerReducer, Router, Route } from 'offramp/redux'; // redux

We use the Provider API to manage your stores throughout the app so we need to import it:

import { Provider } from 'mobx-react'; // mobx
import { Provider } from 'react-redux'; // redux

If you are using MobX, then you'll need to import your stores and put them in a single store object with the routerStore as follows. This allows Offramp to make your router state available throughout the application:

const stores = {
  // ...stores
  router: routerStore
};

If you are using Redux, we first need to import some utilities from the library:

import { createStore, combineReducers } from 'redux';

Then create your store by combining your reducers and passs in the routerReducer:

const stores = createStore(combineReducers({
  // ...reducers
  router: routerReducer
});

Creating Routes

Routing in Offramp is meant to offer a familiar API and allow you to get your client-side navigation started quickly. To create your routing structure, just define your top level <Router> component that will wrap all your routes. Then to structure your routes, just nest them within the <Router> component and provide each of your routes with the correct compoent to render.

// import your components
import Contact from './components/Contact';
import About from './components/About';

render(
  <Provider store={stores}>
    <Router>
      <Route path='/' component={Main}>
      <Route path='/about' component={About} />
      <Route path='/contact' component={NotFound} />
    </Router>
  </Provider>,
  document.getElementById('root')
);

If you need to support nested routes for your application, just place routes within their immediate parent route component. If any of these children routes need to be an index route, just provide an index property on the expected index route.

// import your components
import Main from './components/Main';
import Home from './components/Home';
import About from './components/About';
import UsersPage from './components/UsersPage';
import NotFound from './components/NotFound';

render(
  <Provider store={stores}>
    <Router>
      <Route path='/' component={Main}>
        <Route index component={Home} />
        <Route path='/about' component={About} />
        <Route path='/users' component={UsersPage} />
      </Route>
      <Route path='*' component={NotFound} />
    </Router>
  </Provider>,
  document.getElementById('root')
);

Router State

Offramp is meant to provide an easy way to handle any expected data when rendering your component. Just declare in your route paths where you expect a parameter and Offramp will make sure both the current URL parameters and query parameters are updated and available directly in your store.

...
<Route path='/users' component={Users}>
  <Route path='/users/:id' component={User} />
</Route>
...

Asynchronous Routes

If you need to support async hooks on a particular URL path, you first need to create a hooks object in a separate file and import it or define your hooks directly in your index.js file.

// index.js

...
const userHooks = {
  beforeEnter() { ... },
  onEnter() { ... },
  beforeExit() { ... },
  onExit() { ... }
}
...

Once your hooks are defined you can pass them down into your components as a prop on that route component.

...
<Route path='/users' component={Users}>
  <Route path='/users/:id' hooks={userHooks} component={User} />
</Route>

Prior to rendering your component, Offramp will check for the existence of any hooks. If a beforeEnter hook exists, Crossing will execute that function and prevent rendering until that function resolves. This means you no longer need to fetch data in life-cycle methods such as with componentWillMount.

Built in Components

Offramp provides a <Link /> component to navigate between your different views. When defining your links, pass a to property on the component which points to the correct URL path and also a tag property which contains the links display text.

<nav>
  <li><Link to='/' tag='Home' /></li>
  <li><Link to='/about' tag='About' /></li>
  <li><Link to='/users' tag='Users' /></li>
</nav>

Upcoming Features

  • Support declarative routing
  • Memoize routes to prevent excessive recursive calls