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 🙏

© 2026 – Pkg Stats / Ryan Hefner

atomous

v0.3.0

Published

> ⚠️ This library is still in beta! While the API is mostly stable it may change in the future. The concepts of the library may also change and the library itself needs battle testing.

Readme

atomous

⚠️ This library is still in beta! While the API is mostly stable it may change in the future. The concepts of the library may also change and the library itself needs battle testing.

An atom-based state manager for React, Preact, Vue, Svelte, SolidJS, and vanilla JS.

  • Atomic. Values are stored per atom instance. No need to call a selector function on every value change.
  • Signals-like. Computed atoms track dependencies automatically.
  • Batchable. Setters can be called in a batch to reduce recomputations.
  • TypeScript-first. This library is written in TypeScript and has good TypeScript support.
  • Framework agnostic. Makes it easy to manipulate the state without any frameworks.

Installation

Use your favorite package manager or a 3rd-party tool to import the library in browser.

npm i atomous
<script src="https://cdn.jsdelivr.net/npm/atomous"></script>
import atomous from 'https://esm.run/atomous'

Example

The $ symbol is not required in atom names, it's just a convenient way to name them.

import { atom } from 'atomous'

const $count = atom(0)

$count.subscribe(count => console.log(`Count is ${count}`))

function increment() {
  $count.update(value => value + 1)
}

increment()

Plugins

Extra atoms

  • persistent - synchronises its value with provided storage (e.g. localStorage or other custom solutions)

Integrations

Usage

Atoms

All atom types can be created via either a function or a class constructor. Value of any type of atom is only initialized on subscribe or a first get call.

Regular atom

Regular atom class. Used to just store a value.

  • Function: atom(<initialValue>, [options])
  • Class: new RegularAtom(<initialValue>, [options])
import { atom } from 'atomous'

const $count = atom(0)

$count.subscribe((count) => {
  console.log(`Count is ${count}`)
})

// Dynamically update the value
$count.update(count => count + 1)

// Set a completely new value
$count.set(123)

Computed atom

This atom computes its value using provided function and automatically tracks used dependencies.

  • Function: computed(<compute>, [options])
  • Class: new ComputedAtom(<compute>, [options])
import { atom, computed } from 'atomous'

const $count = atom(0)
const $double = computed(() => {
  return $count.get() * 2
})

$double.subscribe((double) => {
  console.log(`Double is ${double}`)
})

// Changing any dependency will update the value
$count.update(count => count + 1) // $double will be updated

Computed atoms support setting their value explicitly. It will be replaced with the new computed value when triggered.

import { atom, computed } from 'atomous'

const $firstName = atom('John')
const $lastName = atom('Doe')
const $fullName = computed(() => `${$firstName.get()} ${$lastName.get()}`)

// Set value explicitly
$fullName.set('Jane Smith')

// Update dependencies to update the computed value
$firstName.set('William')
$lastName.set('Miller')

// ... or mark the computed atom to recompute its value
$fullName.reset()

Async atom

This atom is similar to computed atom but is designed for asynchronous data loading.

  • Function: asyncAtom(<source>, <load>, [options])
  • Class: new AsyncAtom(<source>, <load>, [options])

The source parameter can be either an atom or a plain value.

Async atoms also support setting their value explicitly. See Computed atom for example.

import { asyncAtom, atom } from 'atomous'

const $postId = atom(123)
const $postData = asyncAtom($postId, async (postId, signal) => {
  const result = await fetch(`/posts/${postId}`, { signal })
  const json = await result.json()

  return json
})

// State example
$postData.get() // { status: "success", data: { /* data */ } }

// Abort current loading
$postData.abort()

Value options

All atoms accept an options object. It can be used to provide custom compare function or a cleanup callback.

import { atom } from 'atomous'

const $atom = atom({
  value: 'some value',
  dispose() {
    console.log('Disposed')
  }
}, {
  // Used to check if two values equal
  compare(a, b) {
    return a.value === b.value
  },

  // Called with current value when new value is set either explicitly or automatically
  cleanup(obj) {
    obj.dispose()
  }
})

Batches

Sync batch

Atom setters can be called in a batch to reduce recomputations.

  • batch(<callback>)
import { atom, batch, computed } from 'atomous'

const $firstName = atom('John')
const $lastName = atom('Doe')
const $fullName = computed(() => `${$firstName.get()} ${$lastName.get()}`)

// $fullName updates only once with a value equal to 'William Miller'
batch(() => {
  $firstName.set('Jane')
  $lastName.set('Smith')

  $firstName.set('William')
  $lastName.set('Miller')
})

Async batch

Batch has an asynchronous version that supports calling async functions.

import { asyncBatch, atom, computed } from 'atomous'

const $firstName = atom('John')
const $lastName = atom('Doe')
const $fullName = computed(() => `${$firstName.get()} ${$lastName.get()}`)

// $fullName is updated after exiting the batch callback
asyncBatch(async () => {
  $firstName.set('Jane')
  await waitForSomething()
  $lastName.set('Smith')
})

Batching your own callbacks

You can batch your own functions like this:

import { AtomBatch, batch } from 'atomous'

// Batched callbacks are called after exiting the batch callback
batch(() => {
  AtomBatch.addOrRun(callback1)
  AtomBatch.addOrRun(callback2)
})

// Batches can be nested. All callbacks will be called after exiting all batch callbacks
batch(() => {
  AtomBatch.addOrRun(callback1)

  batch(() => {
    AtomBatch.addOrRun(nested1)
    AtomBatch.addOrRun(nested2)
  })

  AtomBatch.addOrRun(callback2)
})

// Running the method outside a batch will run provided callback immediately
AtomBatch.addOrRun(callback)