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

single-source

v1.0.5

Published

simple state managment

Downloads

22

Readme

single-source logo

single-source

Build Status Coverage Status npm version License: MIT

Simple state management in JavaScript applications.

Create a store and connect it to React components.

Take a look at some simple examples here.

import/require

$ npm install single-source
# or yarn add single-source
import { createStore, makeReactConnect } from 'single-source';
// or
const singleSource = require('single-source');
const createStore = singleSource.createStore;
const makeReactConnect = singleSource.makeReactConnect;

createStore( initialState )

import { createStore } from 'single-source';

const initialState = {
    items: [],
    currentLanguage: 'en',
    user: {
        email: '[email protected]',
        firstName: 'Tony',
        lastName: 'Stark'
    }
};

const myStore = createStore(initialState);

.getState( [path] )

get the current state

import { createStore } from 'single-source';

const initialState = {
    items: [],
    currentLanguage: 'en',
    user: {
        email: '[email protected]',
        firstName: 'Tony',
        lastName: 'Stark'
    }
};

const myStore = createStore(initialState);

myStore.getState();
/*{
    items: [],
    currentLanguage: 'en',
    user: {
        email: '[email protected]',
        firstName: 'Tony',
        lastName: 'Stark'
    }
}*/

try this on runkit

Get a reduced state based on the given path

import { createStore } from 'single-source';

const USER_EMAIL = 'user.email';

const initialState = {
    items: [],
    currentLanguage: 'en',
    user: {
        email: '[email protected]',
        firstName: 'Tony',
        lastName: 'Stark'
    }
};

const myStore = createStore(initialState);

myStore.getState(USER_EMAIL);
// '[email protected]'

try this on runkit


.dispatch({ path, payload })

changes the state

import { createStore } from 'single-source';

const USER_EMAIL = 'user.email';

const initialState = {
    items: [],
    currentLanguage: 'en',
    user: {
        email: '[email protected]',
        firstName: 'Tony',
        lastName: 'Stark'
    }
};

const myStore = createStore(initialState);

myStore.dispatch({
    path: USER_EMAIL,
    payload: '[email protected]',
});

myStore.getState(USER_EMAIL);
// '[email protected]'

try this on runkit

process function as payload

If you pass a function as payload it will be executed with the current state (or part of state defiend by "path") as argument.

import { createStore } from 'single-source';

const ITEMS = 'items';
const initialState = {
    items: [1, 2, 3, 4],
    currentLanguage: 'en',
};
const myStore = createStore(initialState);
const square = currentItemsArray => currentItemsArray.map(n => n * n);

myStore.dispatch({
    path: ITEMS,
    payload: square,
});

myStore.getState();
/*{
    items: [1, 4, 9, 16],
    currentLanguage: 'en',
}*/

try this on runkit

NOTE: You can not store a function in your state. Just seralizable data can be stored! A function as payload will always executed to recive seralizable data


.subscribe(path, callback)

import { createStore } from 'single-source';

const CURRENT_LANG = 'currentLanguage';
const initialState = {
    items: [],
    currentLanguage: 'en',
};
const myStore = createStore(initialState);

myStore.subscribe(CURRENT_LANG, (newLanguage) => {
    console.log('the new Language is: ', newLanguage);
})

myStore.dispatch({
    path: CURRENT_LANG,
    payload: 'fr',
});
// log -> 'the new Language is: fr'

try this on runkit

NOTE: If .dipatch does not change data the subscribed callback will not be executed.

import { createStore } from 'single-source';

const CURRENT_LANG = 'currentLanguage';
const initialState = {
    items: [],
    currentLanguage: 'en',
};
const myStore = createStore(initialState);

myStore.subscribe(CURRENT_LANG, (newLanguage) => {
    console.log('the new Language is: ', newLanguage);
})

myStore.dispatch({
    path: CURRENT_LANG,
    payload: 'en',
});

// nothing logged because .dipatch not changed any data

makeReactConnect(React, store, mapObj)(YourComponent)

Connect React Components to the store. No Provider Component needed.

import React from 'react';
import ReactDOM from 'react-dom';
import { makeReactConnect, createStore } from 'single-source';

const initialState = {
    counter: 0,
};

const store = createStore(initialState);
const COUNTER = 'counter';
const increase = n => (n + 1);
const square = n => (n * n);

const handleIncrease = () => store.dispatch({
    path: COUNTER,
    payload: increase,
});

const handleSquare = () => store.dispatch({
    path: COUNTER,
    payload: square,
});

const CounterDisplay = props => (
    <input type={'number'} readOnly value={props.counter || 0} />
);

const ConnectedCounterDisplay = makeReactConnect(
    React,
    store,
    { counter: COUNTER },
)(CounterDisplay);

const App = () => (
    <div className="app">
        <ConnectedCounterDisplay />
        <button onClick={handleIncrease}>+ 1</button>
        <button onClick={handleSquare}>n * n</button>
    </div>
);

ReactDOM.render(
    <App />,
    document.getElementById('root'),
);

try something like this here


Why?

If you are like me you are already thinking in paths when it comes to serializable data. What i call path does not mean something complicated.

{
 user: {
        email: '[email protected]',
        firstName: 'Tony',
        lastName: 'Stark'
    }
}

the path 'user.email' points to '[email protected]'. So the string 'user.email' reduces your data to a specific part of an object.

With this in mind it should be easy to handle bigger states in JavaScript applications. Put paths in constants or create new paths dynamically. Use pure-functions to mutate your state

I hope this small tool helps you decrease the complexity of state management in apps.

If you worked with tools like redux you probably won't replace it with single-source. There are no performance tests for single-source yet.

Thanks for reading!