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

spawn-x

v2.3.10

Published

Reactive management for javaScript applications

Downloads

106

Readme

spawn-x

Reactive management for javaScript applications

Spawn

About

Spawn is a simple and super small library (8 kb) without dependencies for reactive management of app state which use modified observer pattern, where instead names of events, uses zones - paths to data into app state.

You can use Spawn independently with another libraryes. Also you may be interested:

install

With npm:

npm install spawn-x --save

With yarn:

yarn add spawn-x
import { createStore } from 'spawn-x';

const store = createStore();

With bower:

bower install spawn-x --save
<script src="path/to/spawn-x/lib/spawn-x.umd.min.js"></script>
var store = Spawn.createStore();

API:

Spawn exports 2 simple functions: createStore() and addInterceptor().

createStore()

This function needed for first initialize store.

// Signature:
createStore(initialState?: any, addInterceptor?: func): instance
// Examples
const store = createStore();

// with initial state
const initialState = {
  hello: 'world'
};
const store = createStore(initialState);

addInterceptor()

This function needed if you want to add interceptors (middlewares). For example interceptor may be as logger.

addInterceptor(interceptor: func, ...): Array<interceptors>
// Examples
const myLoggerInterceptor = store => next => action => {
  console.log('action: ', action);
  next(action);
}
const myOtherInterceptor = store => next => action => next(action);

const store = createStore({}, addInterceptor(myLoggerInterceptor, myOtherInterceptor));

//or without initialState
const store = createStore(addInterceptor(myLoggerInterceptor, myOtherInterceptor));

Store object after initialization will only have 4 methods: select(), detect(), reject(), update()

select()

Method return selected zone from app state. If zone will be equal '*', this method returns full app state. if zone will be a function, method puts the app state in the function argument and apply it.

// Signature:
select(zone: string | func): any 
// Examples:
store.select('foo.bar');
store.select('*'); // full app state
store.select(state => state.foo.bar[2]); // ES2015
store.select(function (state) { return state.foo.bar[2] }); // ES5

detect()

Method makes subscribe for data zone change and apply callback if zone updated. If zone will be equal '*', this method makes subscribe for all changes. Returns instance object.

// Signature:
detect(zone: string, callback: func): instance
// Examples:
const callback = () => {
  const data = store.select('foo.bar');
}

store.detect('foo.bar', callback);

store.detect('*', () => {
  console.log('something happened!');
});

//with receipt of action
store.detect('*', action => {
  if (action.type === 'KARAMBA') {
      store.update('foo', { data: 'bar', type: 'KARAMBA_DETECTED' })
  }
});

reject()

Method for the removal of a callback (unsubscribe).

// Signature:
reject(zone: string, callback: func): instance
// Examples:
const callback = () => {
  const admins = store.select('foo.bar');
}

store.reject('foo.bar', callback);

update()

Method for updates zone. This method takes zone as first argument and action as second. Action must have 'data' field for your data and type. If zone will be equal '*', this method replaces app state on new state and apply all callbacks. It is may be useful to implementation something like time traveling. Returns instance object.

// Signature:
interface IAction {
  data: any;
  type: string;
}

update(zone: string, action: IAction): instance
// Examples:
const admins = [
  { id: 0, name: 'John Doe' },
  { id: 1, name: 'Alex Smith' },
  { id: 2, name: 'Kate Jensen' },
];
const myAction = {
  data: admins,
  type: 'UPDATE_ADMINS'
}
store.update('roles.admins', myAction);

//load app state from localStorage
const myAction = {
  data: JSON.parse(localStorage.getItem('APP_STATE')),
  type: 'LOAD_STATE'
}
store.update('*', myAction);

Note:

You can subscribe on not fully matching zones, and Spawn will runs callbacks correctly. For example: if you subscribe on 'grandpa.parent.child' and will update 'grandpa' or 'grandpa.parent', then 'grandpa.parent.child' will launch own callback. in its turn, if you subscribe on 'grandpa' and will update 'grandpa.parent' or 'grandpa.parent.child', then 'grandpa' will launch own callback.

Example #1

import { createStore } from 'spawn-x';


const store = createStore();

function callback() {
  console.log('name: ', store.select(state => state.users.admins[0].name));
}

//subscribe only on users.admins
store.detect('users.admins', callback);

//update users
store.update('users', {
  data: {
    admins: [
      { id: 0, name: 'John' },
      { id: 1, name: 'Alex' }
    ]
  },
  type: 'UPDATE_USERS'
});
//console output: 'name: John'

setTimeout(() => {
  store.update('users', {
    data: {
      admins: [
        { id: 0, name: 'Jess' },
        { id: 1, name: 'Alex' }
      ],
      some: 'text'
    },
    type: 'UPDATE_USERS'
  });
}, 2000);

//console output: 'name: Jess'

Example #2 "Simple todo app"

import { createStore, addInterceptor } from 'spawn-x';


class TodoApp {
  constructor(store) {
    this.store = store;
    this.store.detect('today.tasks', () => combineActions(this.store.select('today.tasks')));
  }

  addTask(task) {
    const tasks = this.store
      .select('today.tasks')
      .concat(task);

    this.store.update('today.tasks', {
      data: tasks,
      type: 'ADD_TASK'
    });
  }

  removeTask(id) {
    const filteredTasks = this.store
      .select('today.tasks')
      .filter(task => task.id !== id);

    this.store.update('today.tasks', {
      data: filteredTasks,
      type: 'REMOVE_TASK'
    });
  }

  completeTask(id, complete) {
    const updatedTasks = this.store
      .select('today.tasks')
      .map(task => {
        if (task.id === id) {
          task.complete = complete;
        }

        return task;
      });

    this.store.update('today.tasks', {
      data: updatedTasks,
      type: 'CHANGE_COMPLETE'
    });
  }
}

function combineActions(todos) {
  console.log('All todos: ', reportAction(todos));
  console.log('Completed todos:', getCountCompletedAction(todos));
  console.log('-----');
}

function reportAction (todos) {
  return todos.length;
}

function getCountCompletedAction(todos) {
  return todos.filter(todo => todo.complete === true).length;
}

function logger(store) {
  return next => action => {
    console.log('action: ', action.type + ' -> ',  JSON.parse(JSON.stringify(action.data)));
    next(action);
  }
}

///////////////////////////
const initialState = {
  today: {
    tasks: []
  }
};

const store = createStore(
  initialState,
  addInterceptor(logger)
);

const app = new TodoApp(store);

app.addTask({
  id: 0,
  action: 'Learn React',
  complete: true
});

app.addTask({
  id: 1,
  action: 'Learn Angular',
  complete: true
});

app.addTask({
  id: 2,
  action: 'Don\'t be the asshole',
  complete: false
});

app.completeTask(2, true);
app.removeTask(1);

/*
console output:

action:  @@SPAWN/INIT -> ...
All todos:  0
Completed todos: 0
-----
All todos:  1
Completed todos: 1
action: ADD_TASK -> ...
-----
All todos:  2
Completed todos: 2
action: ADD_TASK -> ...
-----
All todos:  3
Completed todos: 2
action: ADD_TASK -> ...
-----
All todos:  3
Completed todos: 3
action: CHANGE_COMPLETE -> ...
-----
All todos:  2
Completed todos: 2
action: REMOVE_TASK -> ...
*/

Example #3 "Redux-like style"

import { createStore } from 'spawn-x';


const btn = document.querySelector('#addTrack');
const input = document.querySelector('#input');
const list = document.querySelector('#trackList');

const store = createStore();

// Constants
const ADD_TRACK = 'ADD_TRACK';
const RENDER_TRACKS = 'RENDER_TRACKS';
const UPDATE_STORE = 'UPDATE_STORE';

// fake Reducer
store.detect('*', action => {
  console.log(action);

  switch(action.type) {
    case ADD_TRACK: {
      store.update('tracks', { 
        type: UPDATE_STORE,
        data: store.select('tracks') ? store.select('tracks').concat(action.data) : [].concat(action.data)
      });
    }
  }
});

// Action Creators
const addTrack = data => {
  store.update('', { 
    type: ADD_TRACK,
    data: data
  });
}

const renderTracks = () => {
  list.innerHTML = '';

  store
  .select('tracks')
  .forEach(item => {
    const li = document.createElement('li');

    li.textContent = item;
    list.appendChild(li);
  });

  store.update('', { 
    type: RENDER_TRACKS,
    data: null
  });
}

btn.addEventListener('click', () => {
  addTrack(input.value);
  renderTracks();
  input.value = '';
});

LICENSE

MIT © Alex Plex