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 🙏

© 2025 – Pkg Stats / Ryan Hefner

valup

v0.2.0

Published

A small, stupid-simple, reactive library.

Readme

Valup

version npm gitlab license codecov

A small, stupid-simple, reactive library.

Why?

Because I wanted to reinvent the wheel.

Actually, because I discovered Solid.js and I find it interesting, especially with its signals. Then, I browsed the source code and found a reference to S.js. I read it and loved it. But the source code of S.js is quite hard for me to understand. So I made my own reactive library.

Is it any good?

I don't know. It works for me I guess so it's not all bad, but I recommend you use a more known project like S.js or a whole solution like Redux. This mainly serves as an educational resource and an example of how such a thing could be implemented in few lines of code. The only case in which I'd recommend using this library is if you're bothered by import size (on browser, minify the project before importing it) or by performance - although I never did any benchmark so I suppose S.js and others could be faster than this project.

Usage

You can create a reactive value with the factory methods of the R class (we'll cover the differences between them later), then update the internal value of the object with the val get/set accessors.

import { R } from './src/index.ts';
const myData = R.data("Hello");
const myStrictValue = R.value("World");
myData.val = myStrictValue.val;
// Events fired...

To add an event handler, you can use either on or addHandler, and remove them with removeHandler.

const counter = R.data(0);
const handler = ({state}: {state: any}) => {
  console.log(`Changed from ${state.prev} to ${state.next}.`);
}

counter.on("changed", handler);
counter.val = counter.val + 1; // "Changed from 0 to 1."
counter.val = counter.val + 1; // "Changed from 1 to 2."

counter.removeHandler("changed", handler);
counter.val = counter.val + 1; // Doesn't log anything.
counter.val = counter.val + 1; // Doesn't log anything.

As you can see in the example above, the "changed" event is already defined internally and is fired after the new value has been set, the state given is of the form {prev: ..., current: ..., next: ..., target: [object R]}. Another predefined event is "changing" which is called right before the new value has been assigned and with the same state structure.

You can also use on to fire custom events instead of just these two, but you have to emit them manually with notify.

const hello = ({state}: {state: any}) => {
  console.log(`Hello, ${state.current}!`);
}
const goodbye = ({state}: {state: any}) => {
  console.log(`Goodbye, ${state.current}.`);
}

const previousUsers = [];
const username = R.data("Alice")
  .on("changing", () => {username.notify("keep-history", {name: username.val})})
  .on("changing", goodbye)
  .on("changed", hello)
  .on("keep-history", ({state}: {state: any}) => { previousUsers.push(state.name) });

username.val = "Bob";
// (previousUsers is now ["Alice"])
// "Goodbye, Alice."
// "Hello, Bob!"
username.val = "Charly";
// (previousUsers is now ["Alice","Bob"])
// "Goodbye, Bob."
// "Hello, Charly!"
username.notify("keep-history", {name: username.val});
// (previousUsers is now ["Alice","Bob","Charly"])

You may want to execute functions only when the value is different and not when it is reassigned to the same thing, in this case, you should use R.value instead of R.data.

const loggedIn = R.value(false)
  .on("changed", console.log.bind(console, "User logged in or logged out."));
loggedIn.val = false;
loggedIn.val = false;
loggedIn.val = true; // "User logged in or logged out."
loggedIn.val = true;
loggedIn.val = true;
loggedIn.val = false; // "User logged in or logged out."

When used with an array or object, you may provide your own equality function to check if the events are to be sent or not.

const jsonEqual = (a: any, b: any) => JSON.stringify(a) === JSON.stringify(b);
const state = R.value({id: 0, logged: false, isAdmin: false}, jsonEqual)
  .on("changed", ({state}: {state: any}) => {
    const event = state.current.logged ? "logged-in" : "logged-out";
    state.notify(event, state);
  })
  .on("logged-in", ({state}: {state: any}) => console.log(`User ${state.current.id} logged in.`))
  .on("logged-out", ({state}: {state: any}) => console.log(`User ${state.current.id} logged out.`));

const toggleLog = (obj: any) => {
  return { ...obj, logged: !obj.logged };
}
state.val = toggleLog(state.val); // "User 0 logged in."
state.val = toggleLog(state.val); // "User 0 logged out."

If your only need in a state is the current value, you can send the currentValue property.

const countdown = R.data(0)
  .on("down", ({state}: {state: any}) => {
    console.log(state.current);
    if (state.current > 0) {
      countdown.val = countdown.val - 1;
    }
  })
  .on("changed", ({state}: {state: any}) => {countdown.notify("down", countdown.currentState)});

countdown.val = 5;
// "5"
// "4"
// "3"
// "2"
// "1"
// "0"

You may watch for multiple values with the static R.onAny method like so.

const c1 = R.data(1);
const c2 = R.data(2);
const c3 = R.data(3);
const handler = ({state}: {state: any}) => {console.log("Something is going on...")}
R.onAny([c1, c2, c3], "changing", handler); // Same as applying the handler to c1, c2 and c3.
R.onAnyChanging([c1, c2, c3], handler); // Shorthand for "changing" event.
R.onAnyChanged([c1, c2, c3], handler); // Shorthand for "changed" event.

License

This is free and unencumbered software released into the public domain. For more information, read the LICENSE file or refer to http://unlicense.org/.