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

buildo-react-container

v0.11.1

Published

helper to build container components (connected to state, queries, commands)

Downloads

12

Readme

Import as

import container from 'buildo-react-container'

All the following should be valid usage examples

export default container(MyComponent)
export default container(MyComponent, {
  connect: { param1: Type1 }
})
export default container(MyComponent, {
  mapProps: ({ a, b }) => ({ aAndB: `${a}&${b}` })
})
export default container(MyComponent, {
  queries: ['query1', 'query2']
})
export default container(MyComponent, {
  commands: ['cmd1']
})

This could be a "typical" usage

export default container(MyComponent, {
  connect: { a: t.String },
  mapProps: ({ a, b, cmd1 }) => ({
    aAndB: `${a}&${b}`,
    onClick: cmd1
  }),
  queries: ['b'],
  commands: ['cmd1']
})

Usage on node and/or SSR project:

When we have a single render shot (SSR on node), we must opt-in to querySync so that at the first render we have all the data we need to produce a full HTML. See also https://github.com/buildo/react-avenger/blob/master/src/queries.js#L38-L47

export default container(MyComponent, {
  querySync: true,
  queries: ['b']
})

If you need to add additional prop types...

(other than the ones derived from queries/commands/connect)

export default container(MyComponent, {
  propTypes: { myProp: MyType },
  // ...
});

Use this forms to configure react-avenger/queries, react-avenger/commands or state/connect

This should be done only once in a project, typically in a custom app/container file or folder.

const containerFactory = container({
  declareConnect: declareConnect(/* declareConnect config */)
  allQueries: { /* all queries */ },
  allCommands: { /* all commands */ }
})

export default containerFactory(MyComponent, {
  /* container cfg */
})

Notes about caching query values in a container instance

When we declare queries in a container we are delegating to avenger (and the query definition) the decision about refetching or not, given a possibly outdated value currently available in the cache.

From the container (component) perspective instead, closer to rendering the actual UI, we have slightly different concerns:

  • should we render a loader if data is nota vailable yet?
  • should we render loading states alongside UI for the data if we are both "loading" and "ready to render"
  • should we wait for "fresh" data before rendering (i.e. if we are both "loading" and "ready to render", should we wait for the updated values aka to be "not loading anymore")

These kind of things are generally solved by customizing a loading decorator, that normally receives the plain data and readyState as avenger produces it.

There are specific cases though, where, as a container instance currently rendering some UI, we need to manipulate intermediate/stale data obtained from avenger before feeding it into our UI/loading. container is per se stateless. Here we need instead to accumulate state between multiple container re-renderings. In this cases we should resort to the reduceQueryProps api:

container(MyComponent, {
  reduceQueryProps: (accumulator: Any, propsFromQueries: PropsFromQueries) => ({
    accumulator: Any,        // accumulator for the next re-render, if needed
    props: PropsFromQueries  // the actual props passed down at this render: you can map/change `readyState` and any query as you wish here
  })
})

Since there are only a few useful known usages, here we'll just list them and explain the use case.

default (no reduceQueryProps)

In the large majority of cases, this is what we want. As soon as we have a value for a query, we'll pass it down. As soon as some event causes the query the refetch, we'll pass the readyState.loading state down as well. We stay stateless.

If the query is refetched with a different input, we'll get notified and loose the previous value we got (it was indeed for a different input) and we pass through a "no data" state. This last example is uncommon since typically, during the whole container lifecycle, inputs for the queries it declares do not change.

cache query values

When the lifecycle of the component spans multiple instances of the same query class (i.e.: the declared query is refetched with different inputs while we are still mounted), we'll typically want to preserve data (and thus UI) across multiple instances.

Two example use cases to clarify:

  • A query that produces a value also based on user input. User writes in a form, the query refetches with new inputs at every keystroke, we need to keep rendering the value computed, even if it was for the previous input.
  • When we have data arranged in a sortable list, and the sorting is performed by the api: if the user sorts by a different param, we'll typically want to:
    • (maybe) show a loader while we are retrieving the updated sorted results
    • keep showing the stale data we have (in other words: avoid passing by "empty list" states, while waiting for the re-sorted data)

For this scenario, container exports a custom reduceQueryProps function called cacheQueryValues. It can be used as follows:

import container, { cacheQueryValues } from 'container';

container(MyComponent, {
  queries: ['sortedData'],
  reduceQueryProps: cacheQueryValues,
  // ...
})