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

vdux-summon

v0.2.10

Published

Summon data for your components

Downloads

68

Readme

summon

js-standard-style

Summon data for your components

Installation

$ npm install vdux-summon

Usage

vdux-summon is inspired by react-refetch. You can use it to declaratively fetch data for your components and inject it into their props. You use it like this:

function render ({props}) {
  return (
    <ul>
      {
        props.activities.value.map(activity => <li>{activity.displayName}</li>)
      }
    </ul>
  )
}
export default summon(props => ({
  'activities': `/user/${props.userId}/activities`
}), {
  render
})

Which you can then use like this:

<Activities userId={currentUser.id} />

Descriptor object

The structure of descriptor objects is:

  • url - String, specifies the URL to fetch. If only a string is specified, it is shorthand for this.
  • fragment - See the pagination/cursor section.
  • merge - Define a custom merge function for fragments.

Data object

The structure of a given object is:

  • loading - Whether or not the collection is currently loading
  • loaded - This is true any time after data has been loaded once. So if you are refetching, this remains true.
  • error - If an error has occurred, it is stored here.
  • value - The value returned from the request.
  • url - The url that was requested (minus any fragments)

Refetching

Whenever the urls generated from props change, the data is refetched.

Pagination/cursors

If you want to add to an existing collection, you can do so using fragments. Fragments are not diffed against the main url, so they do not invalidate the existing collection, and the result of requesting with a fragment will be merged into the existing collection (how this is done is configurable). Example:

summon(props => ({
  'activities': `/user/${props.userId}/activities`,
  more: pageToken => ({
    activities: {
      fragment: `?pageToken=${pageToken}`
    }
  })
}), {
  render: function ({props}) {
    const {activities, more} = props
    const {value} = activities

    return (
      <div>
        <ul>
          {
            value.items.map(activity => <li>{activity.displayName}</li>)
          }
        </ul>
        <button onClick={() => more(value.pageToken)}>Load more</button>
      </div>
    )
  }
})

This will inject a more function into your props which you can call with a pageToken to generate a new fragment. The fragment will be appended to the existing URL for that collection and re-requested, with the result being merged into the existing collection.

Invalidation & Subscription

A unique feature of vdux-summon is its invalidation/subscription capabilities. Each request descriptor may subscribe to a key or list of keys (it is automatically subscribed to the URL of the request). You may then trigger an invalidaton of these keys from elsewhere in the application. For example, consider a follow button:

import summon from 'vdux-summon'

function render ({props}) {
  return (
    <Button onClick={followUser(props.userId)} disabled={props.isFollowing.value}>
      FollowUser
    </Button>
  )
}

export default summon(props => ({
  isFollowing: `/user/following/${props.userId}`
}), {
  render
})

This causes the current user to follow another. But what if there are disparate pieces of UI that rely on this information but have already loaded it? We want them to update too, and we want our button to automatically update itself to indicate that the user is already followed. Let's update our example to make that work:

import summon, {invalidate} from 'vdux-summon'

function render ({props}) {
  return (
    <Button onClick={[followUser(props.userId), () => invalidate(`/user/following/${props.userId}`)]} disabled={props.isFollowing.value}>
      FollowUser
    </Button>
  )
}

export default summon(props => ({
  isFollowing: `/user/following/${props.userId}`
}), {
  render
})

Now not only will the follow button update, but any component that has summoned /user/following/${props.userId} will get refetched and rendered. This makes it easy to keep your data consistent across components.

Middleware

In order to make this work however, you must install the summon middleware in your vdux middleware stack:

import * as summon from 'vdux-summon'

vdux({
  middleware: [...middleware, summon.middleware]
})

Custom invalidation keys

Sometimes you want to invalidate in broader strokes than particular urls, or otherwise decouple the invalidations from the endpoints that they request. To do this, you may add a subscribe key to your descriptor:

summon(props => {
  feed: {
    url: `/user/following/${props.userId}`,
    subscribe: 'feed update'
  }
})

Then somewhere else:

import io from 'socket.io'
import vdux from 'vdux'

const socket = io()

// ... setup vdux...

socket.on('feed update', msg => dispatch(invalidate('feed update')))

License

MIT