Security News
pnpm 10.0.0 Blocks Lifecycle Scripts by Default
pnpm 10 blocks lifecycle scripts by default to improve security, addressing supply chain attack risks but sparking debate over compatibility and workflow changes.
@diotoborg/magnam-dolorem
Advanced tools
> **UPDATES:** > * Version `1.X.X` simplifies the library and introduces breaking changes. > If you're looking for the `0.X.X` documentation (I am _so sorry_), [look here](/README-v-0XX.md), > * Version `1.1.X` adds `typescript` support, and a new `subsc
UPDATES:
- Version
1.X.X
simplifies the library and introduces breaking changes. If you're looking for the0.X.X
documentation (I am so sorry), look here,- Version
1.1.X
addstypescript
support, and a newsubscribeOnce
function (see below)- Version
2.X.X
introducesrxjs
under the hood- Version
3.X.X
replacesrxjs
withimmutablejs
for maximum profit
subscribe
(returns an unsubscription function)getState
If it isn't the simplest state-manager you have ever encountered, I'll ...
I'll eat my very javascript typescript.
npm i -s @diotoborg/magnam-dolorem
This library can be used alone, or in combination with other state managers. Here's what you do:
raphsducks
allows you to intuitively define your state once, in a single place. The libary turns your state representation into an object that you can observe or update in different ways.
The library exports a single function, createState
.
When called, this returns an State
instance, which
/* MyApplicationStore.js */
import createState from '@diotoborg/magnam-dolorem';
// State definition: the object-literal you supply is your initial state.
const initialState = {
todos: [],
someOtherValue: false,
someCounter: 0,
someString: ''
}
// The state instance you will actual use. Instantiate, and you're ready to go.
const store = createState(initialState);
// (OPTIONAL) export for use in other parts of your app
export default store;
Hint: In typescript, a key initialized with
null
will always expectnull
as an update value. To prevent type assertion errors, make sure you initialize your keys with a corresponding type. (e.g.{ p: [] as string[] }
)
In the example above, both todos
and someOtherValue
will become functions on store
. See usage here
When working with TS, you'll want to cast object types in your initial state to avoid type assertion errors. This prevents array types from being initialized as never[]
, and lets the instance know what keys to expect from any child objects.
// A single `To do` object (e.g. for a to-do list)
type ToDo = { title: string, description?: string, done: boolean };
// Initial state with inline type definitions
const initialState = {
todos: [] as ToDo[], // require an array of `ToDo` objects
someOtherValue: false, // boolean (inferred)
someCounter: 0, // number (inferred)
someString: '' as string | null // will allow `null` for this key
}
const myStateInstance = createState(initialState);
// update select keys
myStateInstance.multiple({
someOtherValue: true,
someCounter: 3,
});
// Check results
myStateInstance.getState().someOtherValue; // true
myStateInstance.getState().someCounter; // 3
Note: This requires you to update your state type definition as well as your initial state object.
You can optionally create a type-def for the entire state, though this gets unwieldy to maintain. Inline definitions are cleaner and recommended (see above).
// IMPORTANT: DO NOT specify optional properties on the top level, or you'll
// never hear the end of it.
type MyStateTypeDef = {
todos: ToDo[];
someOtherValue: boolean;
someCounter: number;
someString: stringl
};
// A single `To do` object (e.g. for a to-do list)
type ToDo = { title: string, value: boolean };
// USAGE 1: Type-cast your initial state to get TS warnings for missing properties.
const initialState: MyStateTypeDef = { ... };
const myStateInstance = createState(initialState);
// USAGE 2: Cast the `createState` function to get TS warnings here.
const myStateInstance = createState<MyStateTypeDef>( /* initialState */ );
You can update one key at a time, or several at once. In Typescript, the value type is expected to be the same as the initial value type in state. Other types can usually be inferred.
// Updating one key at a time
store.todos([{ title: "Write code", value: true }]);
// Updating several keys. Subscribers are notified once per 'multiple' call.
store.multiple({
todos: [{ title: "Write code", value: true }],
someOtherValue: true,
});
Note that state.multiple( args )
will merge args
into the current state instance. Make sure you update object properties carefully (e.g. merge Array
properties before supplying them in args
)
// Updating an array property
const oldTodos = store.getState().todos
store.multiple({
todos: [...oldTodos, { title: "New task", value: false }],
someOtherValue: true,
});
You can subscribe for updates and receive an unsubscribe
function. Call it when you no longer need to listen for updates. Your subscriber should take two values: the updated state
values, and a list of just-updated state property names.
const unsubscribe = store.subscribe((state, updatedKeys) => {
let myTodos;
// Handy way to check if a value you care about was updated.
if (updatedKeys.includes("todos")) {
myTodos = state.todos
}
});
// stop listening to state updates
unsubscribe();
state.subscribe()
is a great way to listen to every change that happens to your state. However, you will typically have to check the updated object to see if it has any values you want.
Luckily there are other ways to subscribe to your state instance. These alternatives only notify when something you care about gets updated. Some of them allow you to even specify what values you want to return.
Use subscribeOnce
to listen to your state until a single value is updated (or just until the next state update happens), then auto-unsubscribe.\
Hint: the
listener
handler is the same in allsubscribe
functions. It always accepts two arguments: the updatedstate
object-literal, and a list of keys that were just updated.
You can wait for the next state update to trigger something else.
const unsubscribe = store.subscribeOnce(() => {
doSomethingElse();
});
// Cancel the trigger by unsubscribing:
unsubscribe(); // 'doSomethingElse' won't get called.
Listen until a specific item gets updated, then use it. The value is guaranteed to be on the updated state object.
We'll use state.todos
in our example.
const unsubscribe = store.subscribeOnce((state) => {
const todos = state.todos;
doSomethingElse(todos);
}, 'todos');
// Cancel the state-update trigger by unsubscribing:
unsubscribe(); // 'doSomethingElse' won't get called.
state
instance using the supplied initial state. Parameters:
createState(state: { [x:string]: any }): ApplicationStore
An instance of ApplicationStore
with full subscription capability. This is distinct from your state representation.
A plain JS object literal that you pass into createState
.
This object, for all intents and purposes, is your state. It should hold any properties you want to track.
You can modify/use your state representation via the State Instance
.
createState()
. View full API and method explanations here.
class ApplicationStore {
getState(): ApplicationState;
multiple(changes: Partial<ApplicationState>): void;
reset(clearSubscribers?: boolean): void;
subscribe(listener: ListenerFn): Unsubscriber;
subscribeOnce<K extends keyof ApplicationState>(
listener: ListenerFn,
key?: K,
valueCheck?: (some: ApplicationState[K]) => boolean
): void;
subscribeToKeys<K extends keyof ApplicationState>(
listener: ListenerFn,
keys: K[],
valueCheck?: (key: K, expectedValue: any) => boolean
): Unsubscriber;
// This represents any key in the object passed into 'createState'
[x: string]: StoreUpdaterFn | any;
}
Listener Functions
A listener
is a function that reacts to state updates. It expects one or two arguments:
state: { [x:string]: any }
: the updated state
object.updatedItems: string[]
: a list of keys (state
object properties) that were just updated.A basic Listener receives the updated application state, and the names of any changed properties, as below:
function myListener(updatedState: object, updatedItems: string[]) {
// You can check if your property changed
if (updatedState.todos === myLocalStateCopy.todos) return;
// or just check if it was one of the recently-updated keys
if (!updatedItems.includes("todos")) return;
// `state.someProperty` changed: do something with it! Be somebody!
this.todos = updatedState.todos;
};
You can define your listener
where it makes the most sense (i.e. as either a standalone function or a method on a UI component)
This is a purely in-memory state manager: it does NOT
localStorage
or sessionStorage
).Looking for something? Some items may be in v.0.5.x
documentation, if you can't find them here. Please note that any version below 1.X.X
is very extremely unsupported, and may elicit sympathetic looks and "tsk" noises.
v1x
to v2x
Although not exactly "deprecated", v1.X.X
will receive reduced support as of June 2022. It is recommended that you upgrade to the v2.X.X
libraryas soon as possible. The migration should be as simple as running npm i @diotoborg/magnam-dolorem@latest
, since the underlying API has not changed.
raphsducks
?A publish/subscribe state-management system: originally inspired by Redux, but hyper-simplified.
Raphsducks is a very lightweight library that mainly allows you to instantiate a global state and subscribe to changes made to it, or subsets of it.
You can think of it as a light cross between Redux and PubSub. Or imagine those two libraries got into a fight in a cloning factory, and some of their DNA got mixed in one of those vats of mystery goo that clones things.
createState
function helper for instantiating the stategetState
, and subscribe
methods (for getting a copy of current state, and listening to updates).
subscribe
even returns an unsubscribe function!Actions
.dispatchers
reducers
I didn't. But I like it.
Nope
This is a UI-agnostic library, hatched when I was learning React and (patterns from) Redux. The first implementation came directly from (redux creator) Dan Abramov's egghead.io tutorial, and was much heavier on Redux-style things. Later iterations became simpler, eventually evolving into the current version.
Yes.
No restrictions; only Javascript.
This is, ultimately, a plain JS object. You can use it anywhere you can use JS and need a dynamic in-memory state. It can be restricted to a single component, or used for an entire UI application, or in a command line program. See the examples for UI frameworks.
This is much, *much* simpler to learn and implement.
Redux does a good deal more than raphsducks's humble collection of lines. I wanted something lightweight with the pub/sub API, which would allow me to quickly extend an application's state without getting into fist-fights with opinionated patterns.
As with many JS offerings, I acknowledge that it could be the result of thinking about a problem wrong: use at your discretion.
The core class remains a plain JS object. All dependencies are defined in the package.json
file: as of v2
, the library includes an rxjs
dependency.
git clone https://github.com/diotoborg/magnam-dolorem.git && npm install
Run tests:
npm test
FAQs
> **UPDATES:** > * Version `1.X.X` simplifies the library and introduces breaking changes. > If you're looking for the `0.X.X` documentation (I am _so sorry_), [look here](/README-v-0XX.md), > * Version `1.1.X` adds `typescript` support, and a new `subsc
The npm package @diotoborg/magnam-dolorem receives a total of 0 weekly downloads. As such, @diotoborg/magnam-dolorem popularity was classified as not popular.
We found that @diotoborg/magnam-dolorem demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers 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
pnpm 10 blocks lifecycle scripts by default to improve security, addressing supply chain attack risks but sparking debate over compatibility and workflow changes.
Product
Socket now supports uv.lock files to ensure consistent, secure dependency resolution for Python projects and enhance supply chain security.
Research
Security News
Socket researchers have discovered multiple malicious npm packages targeting Solana private keys, abusing Gmail to exfiltrate the data and drain Solana wallets.