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

react-redux-history

v3.0.0

Published

Navigation history made easy

Downloads

518

Readme

build license npm minsize

⚛ Navigation history made easy!

Lots of applications need more control over their navigation than what their router provides

No worries, we are here to help

Compatible with both react-router v6 and v5 API

📜 Save all navigation history in store   Get started

🌲 Persist history after reloading the page   Read more

⏭️ Skipping screens capability out of the box   Read more

🔀 Dispatch location changes   Read more

👊 Force current route to re-render   Read more

🚦 Selectors for easy access   Read more

🐛 Easy debug, find everything you need to know about navigation in your favorite dev tools:

Setup

Step 1)

Let's get started by installing the package:

pnpm add react-redux-history
npm i react-redux-history
yarn add react-redux-history

Step 2)

Create a browser router and pass it to configureRouterHistory. The returned reducer and middleware will be used to connect to the store:

// store.js
import { configureRouterHistory } from 'react-redux-history'
import { createBrowserRouter } from 'react-router-dom'
import { routes } from 'src/routes'

// optional, defaults are listed below
const options = {
  storageKey: 'routerState',
  storageLimit: Infinity
}

export const router = createBrowserRouter(routes);
export const { routerReducer, routerMiddleware } = configureRouterHistory({ router, ...options })

Backwards compatibility with react-router legacy v5 API is also supported:

// store.js
import { configureRouterHistory } from 'react-redux-history'
import { createBrowserHistory } from 'history'

const options = { ... }

export const history = createBrowserHistory() // react-router legacy v5 API
export const { routerReducer, routerMiddleware } = configureRouterHistory({ history, ...options })

For more info regarding differences between react-router v5 and v6 API check out the official docs

Step 3)

Add the reducer and middleware to your store. If you are using Redux Toolkit it should look something like this:

// store.js
const store = configureStore({
  reducer: combineReducers({
    // ...other reducers
    router: routerReducer
  }),
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware()
      // ...other middleware
      .concat(routerMiddleware)
})

export default store

Step 4)

Lastly, add either <LocationListener /> or useLocationListener somewhere at the root of your app:

// App.tsx
import { useLocationListener, LocationListener } from 'react-redux-history'
// use the `history` object if working with `react-router` v5 API
import { router } from 'src/store'

const App = () => {
  useLocationListener(router) // use either this or the component below, not both!
  
  return (
    <>
      ...
      <LocationListener router={router} /> 
      ...
    </>
  )
}

Note: the router / history objects provided to configureRouterHistory and useLocationListener / LocationListener must be the same objects !

Configuration

The middleware can be configured by passing an options object as the second argument to configureRouterHistory.

The following options are available:

  • storageKey - the key to use when saving the state to session storage. Defaults to routerState
  • storageLimit - the maximum number of entries to save in session storage. Defaults to Infinity

Be careful when limiting session storage entries. The user is still able to go back to previous pages even if they are not saved in session storage. This can cause unexpected behaviour on page reload, especially if you use skipBack / skipForward or similar logic that alters the navigation flow.

Features

🌲 Persistent history

History is persisted after page refresh by leveraging session storage.

This helps provide a better user experience and allows you to build a more robust navigation system.

⏭️ Skip back / forward

By setting a skipBack / skipForward flag on a specific route the user will be automatically skipped over certain routes.

history.push({
  pathname: 'page_5',
  state: { skipBack: 4 }
})

In this example, every time the user will try to go back from page_5 he will be skipped back 4 pages, reaching page_1. The same behaviour will apply when going forward from page_1, the user will be skipped forward to page_5.

Note: Due to the restrictive nature of browser navigation, back or forward actions cannot be stopped. That means that in the previous example the user will actually reach page_4 before being redirected to page_1. If there is conflicting logic (such as extra redirects) in page_4, it will be fired before the middleware manages to completely skip all screens. In order to get past this issue we can selectIsSkipping to not render the component tree while skipping.

We managed this at Utilmond by leveraging the selector in our general purpose loading component. When the flag is true, we render a loading backdrop instead of the current route. This prevents any conflicting logic to be fired and mess with the redirects.

🔀 Dispatch location changes

Change current location using redux actions anywhere in your app.

The API is compatible with history, it can be used as a drop-in replacement.

import { push, replace, forward, back, go } from 'react-redux-history'

dispatch(push({
  pathname: 'homepage',
  state: {
    ...
  }
}))

// or use the short version

dispatch(push('homepage'))

👊 Force current route to re-render

Force current route to re-render by using selectForceRender. Navigate to the same route while passing forceRender: {} in location state.

import { useSelector } from 'react-redux'
import { selectForceRender } from 'react-redux-history'

const Component = () => {
  // The component will re-render every time the `forceRender` flag reference changes
  const forceRender = useSelector(selectForceRender)

  useEffect(() => {
    // The flag can also be used as a dependency in order to re-trigger effects
  }, [forceRender])

  return (
    <button
      onClick={() => {
        history.push({
          // By default `react-router` will not trigger re-rendering when the pathname is the same
          pathname: 'current_pathname',
          state: {
            // Simply pass a new object to force re-rendering
            forceRender: {}
          },
        })
      }}
    >
      Re-render
    </button>
  )
}

🚦 Selectors for easy access

There are also a few useful selectors for easy access:

  • selectLocationHistory
  • selectCurrentLocation
  • selectCurrentLocationState
  • selectCurrentLocationIndex
  • selectNextLocation
  • selectPreviousLocation
  • selectBackLocation
  • selectHistoryAction
  • selectIsSkippingRoutes
  • selectIsNewSession
  • selectForceRender

🚀 Powered by

Used in production by Utilmond

react redux react-router