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

@novas/substate

v0.0.1-alpha.4

Published

1kb subscription-based state hooks for React

Downloads

8

Readme

@novas/substate

1kb subscription-based state hooks for React

Installation

yarn add @novas/substate

Motivation

Allow child components to create and subscribe to keyed stateful values on a parent ContextProvider and re-render only when necessary, without memoization at the component level. 1kb and no dependencies.

Example

import {
	useSubState,
	useCreateSubState,
	SubStateProvider,
} from '@novas/substate'
import { useRef, useEffect } from 'react'

const Parent = ({ children }) => {
	const api = useCreateSubState()
	return <SubStateProvider value={api}>{children}</SubStateProvider>
}

const Child = ({ id, children }) => {
	const { state, setState, store } = useSubState(id)
	const renderCount = useRef(0)
	useEffect(() => void renderCount.current++)
	return (
		<p>
			<h2>Child {id}</h2>
			<span>Render count: {renderCount.current}</span>
			<span>Current value: {state}</span>
			<button onClick={() => setState(Math.random())}>
				Re-render child {id}
			</button>
		</p>
	)
}

const Page = () => (
	<Parent>
		<Child id="1" />
		<Child id="2" />
		<Child id="3" />
		<Child id={3} />
	</Parent>
)

Usage

The store must be an object. Do not mutate state directly, use the setter functions.

  1. useCreateSubState to create the store api and pass it to a SubStateProvider
import { useCreateSubState, SubStateProvider } from '@novas/substate'

const MyComponent = ({ children }) => {
	const api = useCreateSubState()
	return <SubStateProvider value={api}>{children}</SubStateProvider>
}
  1. useSubState to create and subscribe to keyed values in the store from a child component. It will only cause re-renders when the store value with that specific key changes. Multiple components can subscribe to the same key.
const { state, setState } = useSubState('test')
  1. setState accepts a value or merging function, just like React.
setState({ hello: 'world' })
setState((currentState) => currentState++)
  1. useSubState also returns the entire store and store update function.
const { state, setState, store, setStore } = useSubState('test')
// state === store.test
  1. setStore accepts a key and a value or merging function. A string key will update a single key in the store, while undefined will update the entire store. Updating the entire store will re-render all components subscribed to that store. The store must be an object.
setStore('test', { hello: 'world' })
setStore(undefined, { test: { hello: 'world' } })
  1. useSubState without a key will subscribe to the entire store. This will cause re-renders any time a value in the store changes, and allow setting the entire store with setState. The store must be an object.
const { state, setState, store, setStore } = useSubState()
// state === store
// setState === ((value) => setStore(undefined, value))
  1. useSubState accepts an optional initial value. If two components with the same key have different initial values, the component that mounts later will overwrite the first. This works for individual keys, or the entire store. The store must be an object.
const { state: count, setState: setCount } = useSubState('test', 2)
const { store, setStore } = useSubState(undefined, { test: 1 })