{"id":15906055,"url":"https://github.com/atellmer/spawn-x","last_synced_at":"2025-03-21T11:32:24.294Z","repository":{"id":57367067,"uuid":"72571864","full_name":"atellmer/spawn-x","owner":"atellmer","description":"Reactive management for javaScript applications","archived":false,"fork":false,"pushed_at":"2017-03-16T08:59:39.000Z","size":323,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-10-13T13:58:11.323Z","etag":null,"topics":["angular","flux","javascript","mobx","observer","react","reactive","redux","state","store","zone"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/atellmer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-11-01T20:02:43.000Z","updated_at":"2018-05-02T08:52:06.000Z","dependencies_parsed_at":"2022-08-23T20:11:07.291Z","dependency_job_id":null,"html_url":"https://github.com/atellmer/spawn-x","commit_stats":null,"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atellmer%2Fspawn-x","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atellmer%2Fspawn-x/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atellmer%2Fspawn-x/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atellmer%2Fspawn-x/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/atellmer","download_url":"https://codeload.github.com/atellmer/spawn-x/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221814839,"owners_count":16885070,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular","flux","javascript","mobx","observer","react","reactive","redux","state","store","zone"],"created_at":"2024-10-06T13:20:45.322Z","updated_at":"2024-10-28T10:02:55.475Z","avatar_url":"https://github.com/atellmer.png","language":"JavaScript","readme":"# spawn-x\n\n### Reactive management for javaScript applications\n\n![Spawn](./assets/cover.jpg)\n\n## About\nSpawn 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.\n\nYou can use Spawn independently with another libraryes.\nAlso you may be interested: \n* [spawn-x-effects](https://github.com/atellmer/spawn-x-effects) (Interceptor for cascade update)\n* [react-spawn-x](https://github.com/atellmer/react-spawn-x) (React connector for Spawn)\n* [angular-spawn-x](https://github.com/atellmer/angular-spawn-x) (Angular connector for Spawn)\n* [angularjs-spawn-x](https://github.com/atellmer/angularjs-spawn-x) (AngularJS connector for Spawn)\n\n\n## install\nWith npm:\n```\nnpm install spawn-x --save\n```\nWith yarn:\n```\nyarn add spawn-x\n```\n\n```javascript\nimport { createStore } from 'spawn-x';\n\nconst store = createStore();\n```\nWith bower:\n```\nbower install spawn-x --save\n```\n```html\n\u003cscript src=\"path/to/spawn-x/lib/spawn-x.umd.min.js\"\u003e\u003c/script\u003e\n```\n```javascript\nvar store = Spawn.createStore();\n```\n\n## API:\n#### Spawn exports 2 simple functions: createStore() and addInterceptor().\n\n#### createStore()\nThis function needed for first initialize store.\n```javascript\n// Signature:\ncreateStore(initialState?: any, addInterceptor?: func): instance\n```\n```javascript\n// Examples\nconst store = createStore();\n\n// with initial state\nconst initialState = {\n  hello: 'world'\n};\nconst store = createStore(initialState);\n```\n\n#### addInterceptor()\nThis function needed if you want to add interceptors (middlewares). For example interceptor may be as logger.\n```javascript\naddInterceptor(interceptor: func, ...): Array\u003cinterceptors\u003e\n```\n```javascript\n// Examples\nconst myLoggerInterceptor = store =\u003e next =\u003e action =\u003e {\n  console.log('action: ', action);\n  next(action);\n}\nconst myOtherInterceptor = store =\u003e next =\u003e action =\u003e next(action);\n\nconst store = createStore({}, addInterceptor(myLoggerInterceptor, myOtherInterceptor));\n\n//or without initialState\nconst store = createStore(addInterceptor(myLoggerInterceptor, myOtherInterceptor));\n```\n\n#### Store object after initialization will only have 4 methods: select(), detect(), reject(), update()\n\n#### select()\nMethod 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.\n```javascript\n// Signature:\nselect(zone: string | func): any \n```\n```javascript\n// Examples:\nstore.select('foo.bar');\nstore.select('*'); // full app state\nstore.select(state =\u003e state.foo.bar[2]); // ES2015\nstore.select(function (state) { return state.foo.bar[2] }); // ES5\n```\n\n#### detect()\nMethod 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. \n\n```javascript\n// Signature:\ndetect(zone: string, callback: func): instance\n```\n```javascript\n// Examples:\nconst callback = () =\u003e {\n  const data = store.select('foo.bar');\n}\n\nstore.detect('foo.bar', callback);\n\nstore.detect('*', () =\u003e {\n  console.log('something happened!');\n});\n\n//with receipt of action\nstore.detect('*', action =\u003e {\n  if (action.type === 'KARAMBA') {\n      store.update('foo', { data: 'bar', type: 'KARAMBA_DETECTED' })\n  }\n});\n```\n#### reject()\nMethod for the removal of a callback (unsubscribe).\n\n```javascript\n// Signature:\nreject(zone: string, callback: func): instance\n```\n```javascript\n// Examples:\nconst callback = () =\u003e {\n  const admins = store.select('foo.bar');\n}\n\nstore.reject('foo.bar', callback);\n```\n\n#### update()\nMethod 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.\n```javascript\n// Signature:\ninterface IAction {\n  data: any;\n  type: string;\n}\n\nupdate(zone: string, action: IAction): instance\n```\n```javascript\n// Examples:\nconst admins = [\n  { id: 0, name: 'John Doe' },\n  { id: 1, name: 'Alex Smith' },\n  { id: 2, name: 'Kate Jensen' },\n];\nconst myAction = {\n  data: admins,\n  type: 'UPDATE_ADMINS'\n}\nstore.update('roles.admins', myAction);\n\n//load app state from localStorage\nconst myAction = {\n  data: JSON.parse(localStorage.getItem('APP_STATE')),\n  type: 'LOAD_STATE'\n}\nstore.update('*', myAction);\n```\n\n#### Note:\nYou 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.\n\n#### Example #1\n```javascript\nimport { createStore } from 'spawn-x';\n\n\nconst store = createStore();\n\nfunction callback() {\n  console.log('name: ', store.select(state =\u003e state.users.admins[0].name));\n}\n\n//subscribe only on users.admins\nstore.detect('users.admins', callback);\n\n//update users\nstore.update('users', {\n  data: {\n    admins: [\n      { id: 0, name: 'John' },\n      { id: 1, name: 'Alex' }\n    ]\n  },\n  type: 'UPDATE_USERS'\n});\n//console output: 'name: John'\n\nsetTimeout(() =\u003e {\n  store.update('users', {\n    data: {\n      admins: [\n        { id: 0, name: 'Jess' },\n        { id: 1, name: 'Alex' }\n      ],\n      some: 'text'\n    },\n    type: 'UPDATE_USERS'\n  });\n}, 2000);\n\n//console output: 'name: Jess'\n```\n#### Example #2 \"Simple todo app\"\n```javascript\nimport { createStore, addInterceptor } from 'spawn-x';\n\n\nclass TodoApp {\n  constructor(store) {\n    this.store = store;\n    this.store.detect('today.tasks', () =\u003e combineActions(this.store.select('today.tasks')));\n  }\n\n  addTask(task) {\n    const tasks = this.store\n      .select('today.tasks')\n      .concat(task);\n\n    this.store.update('today.tasks', {\n      data: tasks,\n      type: 'ADD_TASK'\n    });\n  }\n\n  removeTask(id) {\n    const filteredTasks = this.store\n      .select('today.tasks')\n      .filter(task =\u003e task.id !== id);\n\n    this.store.update('today.tasks', {\n      data: filteredTasks,\n      type: 'REMOVE_TASK'\n    });\n  }\n\n  completeTask(id, complete) {\n    const updatedTasks = this.store\n      .select('today.tasks')\n      .map(task =\u003e {\n        if (task.id === id) {\n          task.complete = complete;\n        }\n\n        return task;\n      });\n\n    this.store.update('today.tasks', {\n      data: updatedTasks,\n      type: 'CHANGE_COMPLETE'\n    });\n  }\n}\n\nfunction combineActions(todos) {\n  console.log('All todos: ', reportAction(todos));\n  console.log('Completed todos:', getCountCompletedAction(todos));\n  console.log('-----');\n}\n\nfunction reportAction (todos) {\n  return todos.length;\n}\n\nfunction getCountCompletedAction(todos) {\n  return todos.filter(todo =\u003e todo.complete === true).length;\n}\n\nfunction logger(store) {\n  return next =\u003e action =\u003e {\n    console.log('action: ', action.type + ' -\u003e ',  JSON.parse(JSON.stringify(action.data)));\n    next(action);\n  }\n}\n\n///////////////////////////\nconst initialState = {\n  today: {\n    tasks: []\n  }\n};\n\nconst store = createStore(\n  initialState,\n  addInterceptor(logger)\n);\n\nconst app = new TodoApp(store);\n\napp.addTask({\n  id: 0,\n  action: 'Learn React',\n  complete: true\n});\n\napp.addTask({\n  id: 1,\n  action: 'Learn Angular',\n  complete: true\n});\n\napp.addTask({\n  id: 2,\n  action: 'Don\\'t be the asshole',\n  complete: false\n});\n\napp.completeTask(2, true);\napp.removeTask(1);\n\n/*\nconsole output:\n\naction:  @@SPAWN/INIT -\u003e ...\nAll todos:  0\nCompleted todos: 0\n-----\nAll todos:  1\nCompleted todos: 1\naction: ADD_TASK -\u003e ...\n-----\nAll todos:  2\nCompleted todos: 2\naction: ADD_TASK -\u003e ...\n-----\nAll todos:  3\nCompleted todos: 2\naction: ADD_TASK -\u003e ...\n-----\nAll todos:  3\nCompleted todos: 3\naction: CHANGE_COMPLETE -\u003e ...\n-----\nAll todos:  2\nCompleted todos: 2\naction: REMOVE_TASK -\u003e ...\n*/\n```\n#### Example #3 \"Redux-like style\"\n```javascript\nimport { createStore } from 'spawn-x';\n\n\nconst btn = document.querySelector('#addTrack');\nconst input = document.querySelector('#input');\nconst list = document.querySelector('#trackList');\n\nconst store = createStore();\n\n// Constants\nconst ADD_TRACK = 'ADD_TRACK';\nconst RENDER_TRACKS = 'RENDER_TRACKS';\nconst UPDATE_STORE = 'UPDATE_STORE';\n\n// fake Reducer\nstore.detect('*', action =\u003e {\n  console.log(action);\n\n  switch(action.type) {\n    case ADD_TRACK: {\n      store.update('tracks', { \n        type: UPDATE_STORE,\n        data: store.select('tracks') ? store.select('tracks').concat(action.data) : [].concat(action.data)\n      });\n    }\n  }\n});\n\n// Action Creators\nconst addTrack = data =\u003e {\n  store.update('', { \n    type: ADD_TRACK,\n    data: data\n  });\n}\n\nconst renderTracks = () =\u003e {\n  list.innerHTML = '';\n\n  store\n  .select('tracks')\n  .forEach(item =\u003e {\n    const li = document.createElement('li');\n\n    li.textContent = item;\n    list.appendChild(li);\n  });\n\n  store.update('', { \n    type: RENDER_TRACKS,\n    data: null\n  });\n}\n\nbtn.addEventListener('click', () =\u003e {\n  addTrack(input.value);\n  renderTracks();\n  input.value = '';\n});\n```\n\n## LICENSE\n\nMIT © [Alex Plex](https://github.com/atellmer)","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fatellmer%2Fspawn-x","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fatellmer%2Fspawn-x","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fatellmer%2Fspawn-x/lists"}