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

brainstem-redux

v1.0.1

Published

Client-side Brainstem store in Redux

Downloads

459

Readme

brainstem-redux

  • Brainstem-redux syncs data between your Brainstem storage manager and your Redux store
  • Provides (thunked) action creators
    • Model fetching
    • Model saving
    • Collection fetching
  • Provides a "type creator" that provides functions for working with models and collections

npm version npm downloads

Table of Contents

  1. Dependencies
  2. Usage
  3. API
  4. Contributing (and local development)

Dependencies

npm install --save brainstem-js redux redux-thunk

Usage

Use Brainstem-redux when creating your top-level reducer and your store.

  1. Apply the brainstem-redux reducer with the key of brainstem.
  2. When you create your store, apply the updateStorageManager middleware (syncs store -> storage manager)
  3. Finally, set up event handlers to sync the storage manager -> store
const {
  reducer: brainstemReducer,
  updateStore,
  updateStorageManager
} = require('brainstem-redux')

const {
  combineReducers,
  createStore,
  applyMiddleware
} = require('redux')

const thunkMiddleware = require('redux-thunk').default

// 1
const appReducer = combineReducers({
  brainstem: brainstemReducer,
  otherReducers: ...
})

// 2
const storeMiddleware = applyMiddleware(thunkMiddleware, updateStorageManager)

const store = createStore(appReducer, storeMiddleware)

// 3
require('lib/sync/update-store')(store);

Create Brainstem-redux type objects

A "type" is a family of functions that operate on objects with a given shape. In the case of this library, the objects will be the models and collections in the store.

Brainstem-redux provides makeBrainstemType, a factory function that returns an object containing a set of handy functions for working with your models and collections.

Creating a Type

To create a type, use makeBrainstemType:

const { makeBrainstemType } = require('brainstem-redux');

module.exports = makeBrainstemType('posts');

If you want to add some of your own application-specific type functions, you can merge your functions using Object.assign or similar function:

const { makeBrainstemType } = require('brainstem-redux');

function doSomethingWithPost(post) {
  // ...
}

module.exports = Object.assign({},
  makeBrainstemType('posts'),
  {
    doSomethingWithPost,
  },
);

makeBrainstemType also takes an optional typeOptions argument. Currently, it supports a filterPredicate key that allows you to return only a subset of the models in a collection:

const { makeBrainstemType } = require('brainstem-redux');

module.exports = makeBrainstemType('posts', { filterPredicate: post => !post.published });

Using a Type

Once you've defined your type, you can use its functions in your application.

Action Creators

makeBrainstemType provides action creators that wrap the modelActions and collectionActions discussed below.

  • fetchAll(options)

Fetch a collection (wraps collectionActions.fetch).

const { makeBrainstemType } = require('brainstem-redux');

const Post = makeBrainstemType('posts');

Post.fetchAll({
  fetchOptions: {
    include: ['subject']
  }
});
  • fetch(id, options)

Fetch a model (wraps modelActions.fetch).

const { makeBrainstemType } = require('brainstem-redux');

const Post = makeBrainstemType('posts');

Post.fetch(42, {
  fetchOptions: {
    include: ['subject']
  }
});
  • save(id, options)

Save a model (wraps modelActions.save)

Creating a new model:

const { makeBrainstemType } = require('brainstem-redux');

const Post = makeBrainstemType('posts');

Post.save(null, {
  title: 'New post'
});

Updating an existing model:

const { makeBrainstemType } = require('brainstem-redux');

const Post = makeBrainstemType('posts');

Post.save(42, {
  title: 'Update post'
});
  • destroy(id)

Destroy a model (wraps modelActions.destroy).

const { makeBrainstemType } = require('brainstem-redux');

const Post = makeBrainstemType('posts');

Post.destroy(42);

Selectors

makeBrainstemType provides a number of selectors for looking up models.

  • all(state)

Get a lookup table of all objects.

NOTE: This will return all of the models in the Brainstem storage manager, so this should only be used as a lookup table when looking up associated objects, and not as the list of objects you need to display; rather, you should store a list of IDs in your state tree and use findAll or findAllInState to find the objects matching those IDs.

const { makeBrainstemType } = require('brainstem-redux');

const User = makeBrainstemType('users');

function author(users, post) {
  return User.find(post.author_id, users);
}

const Post = Object.assign({},
  makeBrainstemType('posts'),
  {
    author
  }
);

// Elsewhere:
const post = Post.findInState(42, state);
const author = Post.author(User.all(state), post);
  • find(id, collection)

Finds a model by its ID in a lookup object (such as that returned by all).

const { makeBrainstemType } = require('brainstem-redux');

const User = makeBrainstemType('users');

function author(users, post) {
  return User.find(post.author_id, users);
}

// Elsewhere:
const author = Post.author(User.all(state), post);
  • findAll(ids, collection)

Finds a list of models by their IDs in a lookup object (such as that returned by all).

const { makeBrainstemType } = require('brainstem-redux');

const Tag = makeBrainstemType('tags');

function tags(allTags, post) {
  return Tag.findAll(post.tag_ids, allTags);
}

// Elsewhere:
const author = Post.tags(Tag.all(state), post);
  • findInState(id, state)

Finds a model by its ID in the Redux state tree. Assumes that the Brainstem data is at state.brainstem.

const { makeBrainstemType } = require('brainstem-redux');

const Post = makeBrainstemType('posts');

Post.findInState(42, state);
  • findAllInState(ids, state)

Finds a list of models by their IDs in the Redux state tree.

const { makeBrainstemType } = require('brainstem-redux');

const Post = makeBrainstemType('posts');

Post.findAllInState(state.myApp.postIds, state);
  • findInList(id, list)

Finds a model by its ID in a list of models.

const { makeBrainstemType } = require('brainstem-redux');

const Post = makeBrainstemType('posts');

const posts = Post.findAllInState(state.myApp.postIds, state);
const selectedPost = Post.findInList(state.myApp.selectedPostId, posts);

Reducer Helper

Sometimes, you'd like to have one of your application's reducers respond to an action generated by Brainstem-redux (such as SYNC_MODEL or REMOVE_MODEL, for example).

In order to make it easier to determine if the action is appropriate for the model you're working with, you can use matchesAction in your reducer.

const { makeBrainstemType } = require('brainstem-redux');

const Post = makeBrainstemType('posts');

function reducer(state, action) {
  switch (action.type) {
    case: 'SYNC_MODEL':
      return Post.matchesAction(action) : doSomething(state, action) : state;
    // ...
    default:
      return state;
  }
}

Test Helpers

In order to test reducers that respond to Brainstem-redux actions, you need to be able to create actions that match what Brainstem-redux creates.

  • removeModel(model)

Creates a properly-formed REMOVE_MODEL action.

const { makeBrainstemType } = require('brainstem-redux');
const reducer = require('./reducer');

const Post = makeBrainstemType('posts');

describe('My reducer', () => {
  it('removes a model', () => {
    const post = { id: '42', title: 'A Post' };
    const initialState = { postIds: ['42', '58'] };
    const action = Post.removeModel(post);
    const newState = reducer(initialState, action);

    expect(newState).toEqual(['58']);
  });
});
  • syncModel(model)

Creates a properly-formed SYNC_MODEL action.

const { makeBrainstemType } = require('brainstem-redux');
const reducer = require('./reducer');

const Post = makeBrainstemType('posts');

describe('My reducer', () => {
  it('removes a model', () => {
    const post = { id: '42', title: 'A Post' };
    const initialState = { postIds: ['58'] };
    const action = Post.syncModel(post);
    const newState = reducer(initialState, action);

    expect(newState).toEqual(['58', '42']);
  });
});

Use Brainstem-redux action creators

When you want to fetch, save, or destroy your models or fetch your collections, use the modelActions and collectionActions to make sure both your store and storage manager get updated. These action creators feature a few things to facilitate most common usages of fetch / save / destroy.

Each action creator takes an object of options.

  • fetchOptions (object) - fetch options
  • trackKey (string) - unique key to track XHR requests where existing XHRs with the same key are cancelled
  • preFetchAction (action) - action to dispatch before sending the XHR
  • postFetchAction (action creator) - action creator to dispatch after successfully sending the XHR; invoked with the relevant results (e.g. model ID or IDs)
  • Fetch a model
const { modelActions } = require('brainstem-redux')

modelActions.fetch('posts', 42, {
  fetchOptions: {
    include: ['subject']
  }
})
  • Save a model (create)
const { modelActions } = require('brainstem-redux')

modelActions.save('posts', null, {
  title: 'New post'
})
  • Save a model (update)
    • Note that update creates a new Brainstem model and will not make a request if the model is invalid. Adding a reject handler addresses this locally.
const { modelActions } = require('brainstem-redux')

modelActions.save('posts', 42, {
  title: 'Update post'
})
  • Destroy a model
const { modelActions } = require('brainstem-redux')

modelActions.destroy('posts', 42)
  • Fetch a collection
const { collectionActions } = require('brainstem-redux')

collectionActions.fetch('posts', {
  fetchOptions: {
    include: ['subject']
  }
})

API

brainstem-redux API:

  1. reducer: store reducer which manages the top-level brainstem slice of the store
  2. updateStore: event handling of all the collections in your storage manager; dispatches the appropriate actions to the redux store
  3. stopUpdateStore: helper function to stop updating your redux store from your storage manager; invoke with your redux store as the first argument (useful for test cleanup)
  4. updateStorageManager: middleware that syncs the redux store with your storage manager
  5. makeBrainstemType: creates a set of action creators, selectors, and reducer helpers to work with your models
  6. modelActions: action creators for your models
  7. collectionActions: action creators for your collections