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

rehashjs

v1.0.0-alpha.12

Published

Lightweight Redux, for the hash fragment

Downloads

19

Readme

rehash

npm version Travis Build Status

Rehash is a lightweight state container based on Redux and heavily inspired by Redux Zero. Instead of a singleton in-memory store, Rehash uses the browser's hash fragment to store your serialized state.

Installation

yarn add rehashjs

Usage

Import the necessary objects:

import { createStore, JsonSerializer, Provider, connect } from 'rehashjs'

Creating the store

To create a Rehash store, you'll need to define the state of your shape, and the serializer you want to use for each key:

const store = createStore({
  count: JsonSerializer,
})

The keys you specify in createStore will become part of the query string in the hash fragment. For example, if the store had a value of 10 for the count key, the hash fragment might look like this:

#?count=10

Rehash comes with two serializers - DateSerializer, which serializes Dates to epoch millisecond strings, and JsonSerializer, which, well, JSON-serializes things.

Defining Actions

Just like Redux, Rehash uses "actions" to modify application state. Unlike Redux, you don't have to define reducers or action creators - just tell Rehash what your actions are called and provide a reducer implementation.

const actions = {
  increment: (state, payload) => ({ count: state.count + payload }),
}

Your reducer implementation receives the application state when the action is called, but you won't have to worry about that when you're actually calling the action - the connect function curries the reducers for you.

The return value from a Rehash reducer is merged into the program state - so you can return the entire state, just like in Redux, or you can return only what's changed.

If your action doesn't have a payload, the second argument is optional:

const actions = {
  increment: state => ({ count: state.count + 1 }),
}

Many Rehash applications just need to modify the application's state, with no business logic necessary. If that's the case, you can have Rehash auto-generate your actions:

const actions = store.createActionsFromShape()

The generated actions will have the same names as your state keys.

Connecting your application to the store

To connect the store instance to React, use the Provider component:

class App extends Component {
  render() {
    return (
      <Provider store={store}>
        <Counter />
      </Provider>
    )
  }
}

Connecting React components to the store

Just like Redux, Rehash provides a connect function that you can use to connect your components to the Rehash store.

const mapStateToProps = ({ count }) => ({ count })

const Counter = connect(mapStateToProps)(({ count }) => {
  return (
    <div>
      <h1>Count: {count || 0}</h1>
    </div>
  )
})

connect takes two arguments, both optional:

  • mapStateToProps, which extracts values from the Rehash store to pass to the component and must return an object,
  • actions, an object containing actions used by the component

If you don't provide mapStateToProps, the entire state will be passed to the component. The actions and the mapStateToProps return value will be passed to the component as React props.

Updating state

Update the state by calling one of your actions, optionally passing in a payload:

const mapStateToProps = ({ count }) => ({ count })

const actions = {
  increment: (state, payload) => ({ count: state.count + payload }),
}

const Counter = connect(mapStateToProps, actions)(({ count, increment }) => {
  return (
    <div>
      <h1>Count: {count || 0}</h1>
      <button onClick={() => increment(10)}>Increment!</button>
    </div>
  )
})

connect automatically binds actions passed to it to the Rehash store, so you don't have to worry about passing state to the action when you call it. When the action is called, Rehash will run the "reducer" you specified when you defined the action. The object the reducer returns will be merged with the existing Store state and then serialized into the hash fragment.

For the example above, imagine that the hash fragment looked like this:

#?count=10

After clicking the button (and firing the action) with the payload of 10, Rehash will run the increment reducer, which returns a object that looks like this:

{ count: 20 }

...that object will then be passed to a serializer and the hash fragment will be regenerated with the new value:

#?count=20

Serializers

Rehash provides a number of serializers out of the box:

| Serializer | serialize | deserialize | | ------------------ | ---------------------------------------------------------------------- | ----------------------------------------------- | | JsonSerializer | calls JSON.stringify | calls JSON.parse | | DateSerializer | converts a Date object to a string containing millis since the epoch | safely converts an epoch string to a new Date | | StringSerializer | safely calls toString() on the input | returns the input |

Defining your own serializer

Any object with a serialize and deserialize method can serve as a Rehash serializer. Let's make a simple serializer that transforms a Date object into an epoch string:

const DateSerializer = {
  deserialize: dateString => {
    return new Date(Number(dateString))
  },
  serialize: val => {
    return val.getTime().toString()
  },
}

Testing

When testing your connected components with something like Enzyme, the easiest way to render your component in the test is to also render a Provider component, passing in a test store:

describe('myComponent', () => {
  describe('when we load the page', () => {
    it('renders', () => {
      const wrapper = mount(
        <Provider store={store}>
          <MyComponent />
        </Provider>,
      )
    })
  })
})

Rehash provides a createFakeStore function that creates a store backed by an in-memory cache and is otherwise fully functional:

import { createFakeStore, JsonSerializer } from 'rehashjs'

const fakeStore = createFakeStore({
  count: JsonSerializer,
})

If you want to test store integration without mounting the Provider, you can create a fake store and pass it to the connected component's context using the options Enzyme provides when rendering:

import { createFakeStore, JsonSerializer } from 'rehashjs'

describe('myComponent', () => {
  describe('when we load the page', () => {
    it('renders', () => {
      const fakeStore = createFakeStore({
        count: JsonSerializer,
      })

      const wrapper = mount(<MyConnectedComponent />, {
        context: { store: fakeStore },
        childContextTypes: { store: PropTypes.object.isRequired },
      })
    })
  })
})

Alternatively, you can isolate your component by mocking Rehash's connect function:

jest.mock('rehashjs', () => {
  return {
    connect: (mapStateToProps, actions) => component => component,
  }
})

...and then simply pass props to your component as normal:

describe('myComponent', () => {
  describe('when we load the page', () => {
    it('renders', () => {
      const wrapper = mount(<MyComponent aProp={'aValue'} />)
    })
  })
})

Example

There's a sample React app in examples/counter. To start it:

  • yarn install
  • yarn start
  • Visit localhost:3000 in your browser

Roadmap

  • Async/await?
  • Middleware?

Contributing

  1. Fork the repo, clone it, and cd into the directory.
  2. Use Node 8 (nvm use) and install packages (yarn)
  3. Add your feature... and, of course, a test for it.
  4. Run tests with yarn test