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

mutastate

v2.0.19

Published

Mutable state management

Downloads

121

Readme

Description

Mutastate is designed to manage state and send notifications to listeners when state changes.

install

npm install --save mutastate

Api

importables

import Mutastate, {
    withMutastateCreator,
} from 'mutastate';

Mutastate (default import)

The mutastate class, this class is responsible for maintaining state and sending notifications to listeners

import Mutastate from 'mutastate';
const mutastate = new Mutastate();
mutastate.set('foghorn', 'leghorn');
console.log(mutastate.get('foghorn')) // returns leghorn

Functions

  • getAgent(onChangeFunction)
    • Get a new mutastate agent attached to this instance of mutastate
  • getProxyAgent(onChangeFunction)
    • Get a new proxy enabled mutastate agent attached to this instance
  • listen(key, listener = { callback: () => {}}, alias: null, batch: null, transform: null, defaultValue: undefined })
    • listen for changes, notify callback when they occur, defaultValue will directly affect the current data if nothing exists! use batch for easy batch unlistening
  • unlisten(key, callback)
    • Unlisten from a single key with a single known callback function
  • unlistenBatch(batch, basePath)
    • Unlisten from all associated triggers for one given batch which was passed into listen
  • getForListener(key, listener, keyChange)
    • Get data for a given key and listener, this is used by agents to get initial data, and internally to get relevant data upon updating
  • get(key)
    • Get data at a single key, key can be a string with delimiters or an array 'a.b.c[0]' is equivalent to ['a', 'b', 'c', 0]
  • set(key, value, options)
    • Set data.key to value, key can be complex as in get()
  • delete(key)
    • Remove data.key, key can be complex as in get()
  • assign(key, value)
    • Merge value into data.key object, key can be complex as in get()
  • push(key, value, options)
    • Add value to the end of the array at data.key, key can be complex as in get()
  • pop(key, options)
    • Remove final value from the end of the array at data.key, key can be complex as in get()
  • has(key)
    • If the key exists at data.key, return true, otherwise return false, key can be complex as in get()
  • getEverything()
    • return all data for all shards
  • setEverything(data)
    • update all data for all shards
  • addChangeHook(callback)
    • notify callback whenever any data changes, ({ key: [], value: any, meta: { defaultValue: true|undefined, setEverything: true|undefined }}) => {} this is most useful for automated persistence functionality
  • removeChangeHook(callback)
    • stops notifying callback on any data change
  • replicate({ send, primary, ignore, sendInitial, canSetEverything })
    • replicates mutastate to another instance across a network/ipc/rpc

Mutastate Agent

functions

  • new MutastateAgent(mutastateInstance, callbackFunction) or mutastateInstance.getAgent(callbackFunction)
    • Connect to the mutastateInstance and execute callbackFunction when data changes.
  • listen(key, { alias, transform, initialLoad = true, defaultValue } = {})
    • Listen for changes at key in mutastate, then call callbackFunction from the constructor
  • listenFlat(key, { alias, transform, initialLoad = true, defaultValue } = {})
    • Listen for data at key, automatically set alias to the last key section. ['a', 'b', 'c'] sets the alias to 'c'
  • batchListen(childFunction)
    • Execute a lambda, during the lambda execution don't send callback information, after the lambda execute the callback
  • multiListen(listeners, { flat = true } = {})
    • Same as listen or listenFlat, but include a { key } in the listener
  • get(key)
    • Get data at key from mutastate
  • set(key, value)
    • Set data at key in mutastate
  • delete(key)
    • Delete data at key in mutastate
  • assign(baseKey, value)
    • Perform an Object.assign() on the object that is at the baseKey in mutastate
  • push(baseKey, value)
    • Push into an array found at baseKey in mutastate
  • pop(key)
    • Remove the last item in an array found at key
  • has(key)
    • Detect if mutastate contains data at this key
  • assure(key, defaultValue)
    • If has fails on this key, use set at that key with defaultValue
  • getEverything()
    • Return all of mutastate
  • setEverything(data)
    • Overwrite all data in mutastate
  • getAgentData()
    • Get current agent data (including aliased data)
  • pause()
    • Pause callback (data will still flow to the agent unless you manually unlisten)
  • resume()
    • Resume callbacks, you may want to manually re-target information found in getAgentData after resuming
  • resolve(aliasedKey)
    • Resolve an alias to the full mutastate path. agent.listen('a.b.c', { alias: 'bobby' }); then agent.resolve('bobby') will return ['a', 'b', 'c']

Use with React

You can use react hooks like so:

import React from 'react';
import { useMutastate } from 'mutastate';

const randomName = () => ['jerry', 'bobby', 'carl'][Math.floor(Math.random() * 3)];

function Assignment(props) {
    [assignment, setAssignment] = useMutastate(['assignment', props.id]);

    const updateAssignment = (data) => {
        return setAssignment({ ...assignment, ...data });
    }

    return (
        <div>
            <div>{assignment.name}</div>
            <div>{assignment.count}</div>
            <div>{JSON.stringify(assignment.list)}</div>
            <button onClick={() => updateAssignment({ count: assignment.count + 1 })}>Add To Count</button>
            <button onClick={() => updateAssignment({ name: randomName() })}>Change Name</button>
            <button onClick={() => updateAssignment({ list: assigment.list.concat(randomName()) })}>Add To List</button>
        </div>
    );
}

If you want to use traditional react class components you can use a higher order component like so:

This example demonstrates how to create a connected react component, this particular component listens for data in the default shard, under the key ['default', 'assignments', props.id]. This means if the data at that key is updated, this component will receive an update including the new data.

It is important to note that the common pattern of incoming props checking for component updating when using mutastate will not function correctly, unless you make a deep copy of your incoming props for comparison yourself. The data passed into your component will be mutated!

Indicating { useProxy: true } will allow you to modify the data directly (only simple data, objects, arrays, strings, numbers, no custom classes or functions) as we do in this example (see assignment.count += 1). The data will not, in fact, be modified; the modification will be captured and converted into function calls to the current mutastate. (the previous assignment.count += 1 becomes mutastate.set('default.assignments[1].count', assignment.count + 1))

Also please note that the function is withMutastateCreator instead of withMutastate, this is to avoid the ambiguity of having a separate repository for react, this is subject to change in a major version far in the future, currently if you want a withMutastate function you can create one by executing: const withMutastate = withMutastateCreator(React, { instance: yourMutastateInstance, useProxy: true });;

import React from 'react';
import { useMutastate } from 'mutastate';

class Assignment extends React.Component {
    constructor(props) {
        super(props);
        props.agent.listen(['default', 'assignments', props.id], { alias: 'assignment', defaultValue: { name: 'john', count: 0, list: [] } });
    }
    render() {
        const { assignment } = this.props.data;

        return (
            <div>
                <div>{assignment.name}</div>
                <div>{assignment.count}</div>
                <div>{JSON.stringify(assignment.list)}</div>
                <button onClick={() => assignment.count += 1}>Add To Count</button>
                <button onClick={() => assignment.name = ['a', 'b', 'c'][Math.floor(Math.random() * 3)]}>Change Name</button>
                <button onClick={() => assignment.list.push('another')}>Add To List</button>
            </div>
        );
    }
}

export default withMutastateCreator(React, { useProxy: true })(Assignment);

Replication

You can replicate mutastate to secondary instances, useful in circumstances where you don't have direct access to the same mutastate instance such as multi-window electron apps

// start replication, the send function will get called whenever any data in our instance changes (but will ignore changes that came from other instances). In this case we use a fake sendIpcMessage function
const receiver = singleton().replicate({ send: data => sendIpcMessage('state-sync', data) });

// this fictitious listenForIpcMessages function shows how you can receive data from an outside source to update your own mutastate
listenForIpcMessages('state-sync', (sender, data) => receiver(data));

The use of useProxy will limit your browser availability due to use of the Proxy es6 feature:

  • No internet explorer
  • No opera mini
  • Edge 17
  • Firefox 18
  • Chrome 49
  • Safari 10
  • Samsung mobile 5
  • Chrome android 69
  • UC android 11.8

If you must avoid useProxy, the following mutastate methods are available:

  • get(key)
  • set(key, value)
  • delete(key)
  • assign(key, value)
  • push(key, value)
  • pop(key, value)
  • has(key)
  • getEverything(key)
  • setEverything(key)