Skip to content

Instantly share code, notes, and snippets.

@m4n1ok
Last active May 24, 2021 14:24
Show Gist options
  • Save m4n1ok/dd911eca1914753558a80cc41087711f to your computer and use it in GitHub Desktop.
Save m4n1ok/dd911eca1914753558a80cc41087711f to your computer and use it in GitHub Desktop.
Simple store

Usage

import STORE from '@/store'

Register module

STORE.registerModule({
  key: 'bag',
  data: {}
})

Observe store module to run function automaticly on updates

this.stateObserverId = STORE.observe({
          key: 'bag',
          handler: this.updateUI
        })

STORE.unObserve(this.stateObserverId)

Commit and update store

STORE.commit({
        key: 'bag',
        data: {
          item_count,
          total_price,
          items,
          currency,
          openPopup: open
        }
      })
export default ({ target, listener = false }) => {
let observable = null
const set = (target, name, value) => {
target[name] = value
if (listener && typeof listener === 'function') {
listener(observable)
}
return true
}
const get = (target, name) => {
return Object.freeze(target[name])
}
const handler = {
set,
get
}
observable = new Proxy(target, handler)
return observable
}
import observable from '@/helpers/observable'
let instance = null
class Store {
#modules = null
#observers = {}
#observersMap = {}
#listeners = {}
/**
* @return {null}
*/
constructor () {
if (!instance) {
instance = this
}
this.#modules = {}
return instance
}
get state () {
return this.#modules
}
getModule (key) {
if (!this.#modules[key]) {
console.error(`Cannot get state for key ${key}`)
return
}
return this.#modules[key]
}
registerModule ({ key, data }) {
if (this.#modules[key]) {
console.warn(`Cannot register state module ${key}. Module already exist`)
return
}
this.#listeners[key] = () => {
this.runObservers(key)
}
this.#modules[key] = observable(
{
target: {
data: {
...data
},
get: (id) => this.#modules[key].data[id] || null
},
listener: this.#listeners[key]
})
}
deleteModule ({ key }) {
if (this.#modules[key]) delete this.#modules[key]
if (this.#listeners[key]) delete this.#listeners[key]
}
/* State Methods */
commit ({ key, data }) {
if (!this.#modules[key]) {
console.warn(`No Store module register for this key: ${key}`)
return
}
this.#modules[key].data = {
...this.#modules[key].data,
...data
}
}
clean (key) {
this.#modules[key] = {}
}
delete (key) {
if (this.#modules[key]) {
delete this.#modules[key]
}
}
/* Observable Methods */
runObservers (key) {
console.log('runObservers', key)
if (!this.#observers[key]) return
Object.values(this.#observers[key])
.forEach(observer => {
if (typeof observer === 'function') {
observer()
}
})
}
/**
* Add a callback on state update
* @param callback
*/
observe ({ key, handler }) {
if (!this.#observers[key]) {
this.#observers[key] = {}
}
if (!handler || typeof handler !== 'function') {
console.error('State observe callback must be a function')
return
}
const id = Date.now()
this.#observers[key] = {
...this.#observers[key],
[id]: handler
}
this.#observersMap[id] = [key]
return id
}
/**
* Remove callback on state update by id
* @param id
*/
unObserve (id) {
if (!id) {
console.error('State unObserve method needs an id')
return
}
if (this.#observersMap[id] && this.#observers[this.#observersMap[id]]) {
const key = this.#observersMap[id]
console.log('deleteObserver', id)
delete this.#observers[key][id]
if (Object.values(this.#observers[key]).length === 0) {
delete this.#observers[key]
}
}
return null
}
}
const state = new Store()
export default state
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment