single-source

1.0.5 • Public • Published

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: 'tony@stark.com',
        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: 'tony@stark.com',
        firstName: 'Tony',
        lastName: 'Stark'
    }
};
 
const myStore = createStore(initialState);
 
myStore.getState();
/*{
    items: [],
    currentLanguage: 'en',
    user: {
        email: 'tony@stark.com',
        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: 'tony@stark.com',
        firstName: 'Tony',
        lastName: 'Stark'
    }
};
 
const myStore = createStore(initialState);
 
myStore.getState(USER_EMAIL);
// 'tony@stark.com'
 

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: 'tony@stark.com',
        firstName: 'Tony',
        lastName: 'Stark'
    }
};
 
const myStore = createStore(initialState);
 
myStore.dispatch({
    path: USER_EMAIL,
    payload: 'ironman@stark.com',
});
 
myStore.getState(USER_EMAIL);
// 'ironman@stark.com'

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 => (+ 1);
const square = 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</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: 'tony@stark.com',
        firstName: 'Tony',
        lastName: 'Stark'
    }
}

the path 'user.email' points to 'tony@stark.com'. 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!

Versions

Current Tags

  • Version
    Downloads (Last 7 Days)
    • Tag
  • 1.0.5
    2
    • latest

Version History

Package Sidebar

Install

npm i single-source

Weekly Downloads

2

Version

1.0.5

License

MIT

Unpacked Size

275 kB

Total Files

11

Last publish

Collaborators

  • christianheyn