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

@rbxts/silo

v0.2.0

Published

State management

Downloads

4

Readme

Silo

State management based on Redux slices.

Usage

Create a Silo

Creating a new silo is easy. Define the state and modifiers, and then create the silo via createSilo(), passing along the initial state and the modifier implementations.

// Define the shape of the state:
interface MyState {
	kills: number;
	points: number;
}

// Define the modifier actions:
interface MyModifiers {
	addKill: (state: MyState) => MyState;
	addPoints: (state: MyState, points: number) => MyState;
}

// Create the Silo:
const mySilo = createSilo<MyState, MyModifiers>(
	{
		// Default state:
		kills: 0,
		points: 0,
	},
	{
		// Modifier implementations:
		addKill: (state) => {
			return {
				...state,
				kills: state.kills + 1,
			};
		},
		addPoints: (state, points) => {
			return {
				...state,
				points: state.points + points,
			};
		},
	},
);

Modifying state via actions

Modifiers can be accessed through the actions property of a silo. Actions are functions that are identical to the modifier implementation, except the first state argument is dropped, since the silo can inject that itself.

For instance, to use the addKill and addPoints modifiers, we can call the resulting actions as mySilo.actions.addKill and mySilo.actions.addPoints:

// Add kill:
mySilo.actions.addKill();

// Add 15 points:
mySilo.actions.addPoints(15);

Fetching state

Use the getState() function to get the current state of a silo.

print(mySilo.getState());
print(`Points: ${mySilo.getState().points}`);

Listening for state changes

Use the subscribe function to subscribe to all future changes to the entire state, which will also include a copy of the old state.

Use the observe function to observe a specific selection of the state, which will then fire the given observer function anytime the selection changes, including the immediate value.

Observers can optionally be given a changed callback, which will control whether or not the observer is triggered. Any time the silo's state changes, the changed callback will be given the new and old value of the selector, and the callback must return whether or not the value has changed. This is useful for checking for table value changes or other dynamic changes that go beyond the default old !== new comparison.

// Subscribe to changes to the state:
mySilo.subscribe((newState, oldState) => {
	print("State changed");
});

// Observe points:
mySilo.observe((state) => state.points, (points) => {
	print(`Points: ${points}`);
});

// Observing state with a specified `changed` callback:
mySilo.observe(
	(state => state.points),
	(points) => print(points),
	// Only trigger observer if points have changed by more than 5:
	(newPoints, oldPoints) => math.abs(newPoints - oldPoints) > 5,
);

// The `subscribe` and `observe` functions return functions that can be called
// in order to stop subscribing/observing:
const unsubscribe = mySilo.subscribe((newState, oldState) => {});
unsubscribe();

const stopObserving = mySilo.observe((state) => state.points, (points) => {});
stopObserving();

Cleanup

If a silo needs to be cleaned up during runtime, call the destroy() function on the silo. All this function does is clear out the subscriber/observer list internally.

mySilo.destroy();

Combine Silos

It is common to have more than one silo. Use the combineSilo function to create a wrapper silo around multiple silos. The individual silos can still be used, but the combined silo can be used to help manage and observe state.

// Assuming we have the `mySilo` from the first example.

interface AnotherState { message: string }
interface AnotherModifiers {
	setMessage: (state: AnotherState, msg) => AnotherState;
}
const anotherSilo = createSilo<AnotherState, AnotherModifiers>(
	{ message: "" },
	{ setMessage: (state, msg) => ({...state, message: msg}) },
);

// Combine `mySilo` and `anotherSilo`:
const silos = combineSilos({
	my: mySilo,
	another: anotherSilo,
});

// Calling `getState()` returns a combined state of all silos:
print(`Message: ${silos.getState().another.message}`);

// Individual silos can also be accessed through the `all` property:
print(`Message: ${silos.all.another.getState().message}`);

// Observe the current message & future changes to the message:
silos.observe((state) => state.another.message, (msg) => {
	print(`Observing message: ${msg}`);
});

// Set a message:
silos.all.another.actions.setMessage("Hello world");