
Security News
Feross on TBPN: How North Korea Hijacked Axios
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.
Did you ever get tired of the lack of type-safeness or superflous code when using Redux? Or the decorator weirdness using MobX? Then you should npm install abon.
Now, using Abon requires a different approach to state. MobX and Redux, for example, requires you to build your state in a very specific way, and to subscribe to it in a very specific way as well. In Abon's point of view, a value can be stored anywhere, and be used anywhere—inside or outside of components. It can be passed down to components without requiring them to be subscribed to the values, or used inside components without forcing a re-render when updated. That is the immense flexibility that Abon allows for.
To learn more about how Abon can be used, you can check out some of our examples.
AbonAllows for holding, setting and subscribing to a single value. Subscribers are only notified when the set value differs from the current, or if the notify method is used to manually notify subscribers.
import { Abon } from "abon";
const authenticated = new Abon<boolean>(false);
function AuthMessage() {
const auth = authenticated.use().current;
if (!auth) {
return <p>No access</p>;
}
return <p>Welcome</p>;
}
AbonDeepAllows for holding, setting, getting and subscribing to nested values. Subscribers are only notified when the set value differs from the current value (given the keys or lack of keys), or if the notify method is used to manually notify subscribers.
import { AbonDeep } from "abon";
const value = new AbonDeep<{ a: { b: { c: number } } }>({ a: { b: { c: 0 } } });
value.subscribe(
["a", "b", "c"],
(c) => { /** handle a.b.c */ })
);
value.subscribe(
"a",
(a) => { /** handle a */ })
);
value.set({
a: { b: { c: 1 } }
});
value.set("a", "b", "c", 2);
AbonSetExtends Set with additional features allowing for setting and modifying values in one sweep. Whenever a value is added or deleted, subscribers are notified. They can also be notified manually using the notify method.
import { AbonSet } from "abon";
const numbers = new AbonSet<number>([1, 2]);
function DisplayNumbers() {
const numbersAmount = numbers.use().size
if (numbersAmount > 0) {
return <p>No numbers</p>;
}
return <p>Numbers: {numbersAmount}</p>;
}
AbonMapExtends Map with additional features allowing for setting and modifying values in one sweep. Whenever a value is added, modified or deleted, subscribers are notified. They can also be notified manually using the notify method, which accepts a set of keys if only specific keys should be notified.
import { AbonMap } from "abon";
const userFollowers = new AbonMap<string, number>([["james", 10]]);
// [["james", 10]]
userFollowers.delete("james");
// []
userFollowers.set("dude", 12);
// [["dude", 12]]
userFollowers.set({
james: 8,
})
// [["james", 8]]
userFollowers.set({
james: 6,
dude: 10
})
// [["james", 6], ["dude", 10]]
userFollowers.patch({
dude: 12
})
// [["james", 6], ["dude", 12]]
function UserFollowers(props: { userName: string }) {
const followers = userFollowers.use(props.userName);
return <p>Followers: {followers || 0}</p>;
}
function TotalFollowers() {
const totalFollowers = Array.from(userFollowers.use().entries()).reduce(
(totalFollowers, [userName, followers]) => totalFollowers + followers,
0,
);
return <p>Total followers: {totalFollowers || 0}</p>;
}
AbonArrayA subscribable implementation of a normal array, with some additional methods.
import { AbonArray } from "abon";
const indexes = new AbonArray<number>();
indexes.push(2, 4, 5, 9);
const index = indexes.find(index => index > 5); // 9
AbonItemsAllows for dynamically setting, pushing, unshifting, and subscribing to property-identified values.
import { AbonItems } from "abon";
const items = new AbonItems<{ itemId: number; name: string; }, "itemId">("itemId", [{ itemId: 5, name: "Jason" }]);
items.push({ itemId: 2, name: "Luke" })
// items.ids.current: [5, 2]
items.unshift({ itemId: 3, name: "Marie" })
// items.ids.current: [3, 5, 2]
items.set([{ itemId: 7, name: "Mason" }, { itemId: 1, name: "Chlorine" }])
// items.ids.current: [7, 1]
items.delete(7)
// items.ids.current: [1]
// items.items: [{ itemId: 1, name: "Chlorine" }]
// items.current: { 1: { itemId: 1, name: "Chlorine" } }
items.set(5, "name", "Jake")
// does not make difference because an item where `itemId === 5` does not exist
items.set(7, "name", "Charlotte")
// items.items: [{ itemId: 7, name: "Charlotte" }]
items.subscribe((current, items, ids) => {
// items equal ids.map(id => current[id])
})
AbonAsyncAllows for cancelling/overriding the process of setting values that are retrieved asynchronously by providing them as promises. For that purpose, the set methods accepts a promise whose value is to be set once it is resolved unless a different value is set during that time. Additionally, the dispatch method allows for handling promises unrelated to the value, meaning the passed handler is called if no new value is set during the time of the resolution of the passed promise.
import { AbonAsync } from "abon";
const name = new AbonAsync<string>();
const namePromises = [
new Promise((resolve) => setTimeout(() => resolve("Hjalmar"), 100)),
new Promise((resolve) => setTimeout(() => resolve("Sören"), 400)),
new Promise((resolve) => setTimeout(() => resolve("Rory"), 300)),
];
name.set(namePromises[3] /** Promise<"Rory"> */);
name.promise.then((currentName) => { /** "Sören", since it is set last. */ });
name.dispatch(Promise.resolve(), () => { /** Never called, because the next line is set before `Promise.resolve()` has been resolved. */ })
name.set(namePromises[2] /** Promise<"Sören"> */);
name.promise.then((currentName) => { /** "Sören", too. */
name.set(namePromises[0] /** Promise<"Hjalmar"> */);
name.promise.then((currentName) => { /** "Joker", since it is set last. */ });
name.set("Joker");
});
AbonInheritedDownImagine a tree of values, where all branches and sub-branches inherit from their parent, unless they have a value defined themselves. This is useful, for example, for having nodes that can inherit a status from their parents, such as a loading status for form fields in a form.
import { AbonInheritedDown } from "abon";
const value = new AbonInheritedDown<number>(1);
const subValue = value.nest()
const subSubValue = subValue.nest()
value.current // 1, from itself
subSubValue.current // 1, from `value`
subValue.set(2);
subSubValue.current // 2, from `subValue`
subValue.current // 2, from itself
subSubValue.set(3);
subSubValue.current // 3, from itself
subSubValue.set(undefined);
subSubValue.current // 2, from `subValue`
subValue.set(undefined);
subSubValue.current // 1, from `value`
value.set(undefined)
subSubValue.current // undefined
subValue.current // undefined
value.current // undefined
AbonInheritedUpEvery branch looks to itself or to any of its children (added using the addChild method) for a defined value.
import { AbonInheritedDown } from "abon";
const name = new AbonInheritedUp<string>();
const subName = name.addChild();
const subSubName = subName.addChild()
name.current // undefined
subSubName.set("Mike");
name.current // "Mike", from `subSubName`
subName.current // "Mike", from `subSubName`
subSubName.current // "Mike", from itself
subName.set("Oprah");
name.current // "Oprah", from `subName`
subName.current // "Oprah", from itself
subSubName.current // "Mike", from itself
subSubName.set(undefined);
name.current // "Oprah", from `subName`
subName.current // "Oprah", from itself
subSubName.current // undefined
subName.set(undefined);
name.current // undefined
subName.current // undefined
subSubName.current // undefined
The Abon class provides some static utility for composing and constructing the instances described above.
Abon.useComposedValueCreate an Abon with a value based on one or more subscriptions. Dependencies can be passed as a third argument, which means the value will be recalculated if either (1) the listener is notified or (2) the dependencies have changed. Changing the dependencies also re-subscribes (meaning you can change the subscriptions).
There is also Abon.useComposedValueAsync, which allows for returning a promise from the getter function, meaning the value returned from the hook will be undefined at first.
import { Abon, AbonDeep } from "abon";
function PriceStatus() {
const price = Abon.useRef<number>(() => 10);
const fullPrice = Abon.useRef<number>(() => 100);
// `0.1` initially, then updates whenever `price` or `fullPrice` change
const priceFraction = Abon.useComposedValue(
() => price.current / fullPrice.current,
(listener) => [fullPrice.subscribe(listener), price.subscribe(listener)],
[price, fullPrice]
);
if (priceFraction < 0.1) {
return <p>Good price!</p>;
}
return <p>Bad price.</p>;
}
Abon.resolveReturns a promise resolved by the next value set to the provided Abon. You can also pass a function accepting a listener and returning a created subscription, which will resolve the promise with the value that is passed to the listener.
import { Abon } from "abon";
const value = new Abon(0);
Abon.resolve(value).then((_value) => { /** 1 */ })
value.set(1);
FAQs
Flexible state management for React 🚀
The npm package abon receives a total of 32 weekly downloads. As such, abon popularity was classified as not popular.
We found that abon demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.

Security News
OpenSSF has issued a high-severity advisory warning open source developers of an active Slack-based campaign using impersonation to deliver malware.

Research
/Security News
Malicious packages published to npm, PyPI, Go Modules, crates.io, and Packagist impersonate developer tooling to fetch staged malware, steal credentials and wallets, and enable remote access.