All Projects → AriaFallah → Mobx Store

AriaFallah / Mobx Store

Licence: mit
A data store with declarative querying, observable state, and easy undo/redo.

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to Mobx Store

build-relengapi
INACTIVE - http://mzl.la/ghe-archive - Your Interface to Release Engineering Automation -
Stars: ✭ 14 (-95.05%)
Mutual labels:  unmaintained
rilproxy
DEPRECATED
Stars: ✭ 21 (-92.58%)
Mutual labels:  unmaintained
elmo
DEPRECATED - Elmo ~ https://mozilla.github.io/elmo/
Stars: ✭ 32 (-88.69%)
Mutual labels:  unmaintained
calculator
INACTIVE - http://mzl.la/ghe-archive - Resurrection of the calculator app that was pulled from gaia
Stars: ✭ 16 (-94.35%)
Mutual labels:  unmaintained
vinz-clortho
INACTIVE - http://mzl.la/ghe-archive - BrowserID Keymaster for LDAP enabled Identity Providers
Stars: ✭ 16 (-94.35%)
Mutual labels:  unmaintained
Garmr
INACTIVE - Security Testing Tool
Stars: ✭ 105 (-62.9%)
Mutual labels:  unmaintained
silan
audio file [silence] analyzer
Stars: ✭ 33 (-88.34%)
Mutual labels:  unmaintained
Colors Of Image
A PHP Library for getting colors from images DEPRECATED
Stars: ✭ 273 (-3.53%)
Mutual labels:  unmaintained
jade-babel
Jade plugin for Babel
Stars: ✭ 39 (-86.22%)
Mutual labels:  unmaintained
rescuefox
DEPRECATED - demo game to drive 3D engine creation: rescue your pet space fox!
Stars: ✭ 35 (-87.63%)
Mutual labels:  unmaintained
page-metadata-service
DEPRECATED - A RESTful service that returns the metadata about a given URL.
Stars: ✭ 18 (-93.64%)
Mutual labels:  unmaintained
2015-foia-hub
A consolidated FOIA request hub.
Stars: ✭ 47 (-83.39%)
Mutual labels:  unmaintained
addon-sdk-content-scripts
DEPRECATED | Use WebExtensions instead | Add-ons demonstrating how to use content scripts in the Add-on SDK.
Stars: ✭ 23 (-91.87%)
Mutual labels:  unmaintained
icongrid
INACTIVE - http://mzl.la/ghe-archive - IconGrid.js makes it easy to display a scrollable grid of icons!
Stars: ✭ 25 (-91.17%)
Mutual labels:  unmaintained
coma
a console mail user agent | obsolete: use mblaze
Stars: ✭ 13 (-95.41%)
Mutual labels:  unmaintained
soup
INACTIVE - http://mzl.la/ghe-archive - OpenWebApps on Android
Stars: ✭ 12 (-95.76%)
Mutual labels:  unmaintained
id-specs
INACTIVE - http://mzl.la/ghe-archive - Specifications for Mozilla's Identity Effort
Stars: ✭ 91 (-67.84%)
Mutual labels:  unmaintained
Wifi
[unmaintained] WiFi tools for linux
Stars: ✭ 281 (-0.71%)
Mutual labels:  unmaintained
confidential-survey
A Rails app for conducting confidential surveys without violating user privacy
Stars: ✭ 29 (-89.75%)
Mutual labels:  unmaintained
web-forward
DEPRECATED - Innovation acceleration program from Mozilla Labs
Stars: ✭ 17 (-93.99%)
Mutual labels:  unmaintained

mobx-store

CircleCI npm Coveralls

A data store with declarative querying, observable state, and easy undo/redo.

Why

Query your data declaratively like it is SQL

import mobxstore from 'mobx-store'
import { filter, map, pick, sortBy, take } from 'lodash/fp'

// Create store
const store = mobxstore({ users: [] })

// SELECT name, age FROM users WHERE age > 18 ORDER BY age LIMIT 1
store('users', [map(pick(['name', 'age'])), filter((x) => x.age > 18), sortBy('age'), take(1)])

Schedule reactions to state changes

import mobxstore from 'mobx-store'
import { filter } from 'lodash/fp'

function log(store) {
  console.log(store('numbers', filter((x) => x > 10)))
}

// Create empty store
const store = mobxstore({ numbers: [] })

// Schedule log so that it happens every time the store mutates
store.schedule([log, store])

// log is invoked on the push because the store mutated
store('numbers').push(1)
/*
  logs [] because 1 < 10
*/

// log is invoked on the push because the store mutated
store('numbers').push(12)
/*
  logs [12]
*/

Easy undo and redo

store('test').push(1, 2, 3) // value of test is [1, 2, 3]
store.undo('test') // value of test is [] again
store.redo('test') // value of test is [1, 2, 3] again

Easy interop with React

One of the best things about the store is that you can use it with mobx-react because it's based upon MobX. This also means that when you mutate your objects you don't need setState() calls because MobX will handle all the updating for you.

import React from 'react'
import mobxstore from 'mobx-store'
import { observer } from 'mobx-react'

const store = mobxstore({ objects: [] })

const Objects = observer(function() {
  function addCard() {
    store('objects').push({ name: 'test' })
  }
  return (
    <div>
      <button onClick={addCard}>Add New Card</button>
      <div>
        {store('objects').map((o, n) =>
          <div key={n}>
            {o.name}
          </div>
        )}
      </div>
    </div>
  )
})

export default Objects

Example

Here's a quick demo I put together to demonstrate the observable state and undo/redo features. It uses the code you can find later in the README to make changes to the store automatically persist to localstorage.

Installation

npm install --save mobx-store

Keeping your bundle small

If you're concerned about the extra weight that lodash will add to your bundle you can install babel-plugin-lodash

npm install --save-dev babel-plugin-lodash

and add it to your .babelrc

{
  "presets": // es2015, stage-whatever
  "plugins": [/* other plugins */, "lodash"]
}

this way you can do modular imports, and reduce the size of your bundles on the frontend

import { map, take, sortBy } from 'lodash/fp'

Tutorial

The store is structured as an object that holds either an array or object for each key. For example, something like

{
  numbers: [],
  ui: {}
}

To create a store all you need to do is

import mobxstore from 'mobx-store'

// Create empty store and initialize later
const store = mobxstore()
store.set('users', [])

// Create store with initial state
const store = mobxstore({
  users: [{ name: 'joe', id: 1 }]
})

and to get access to specific key such as users you would just call.

store('users')

With arrays you can manipulate them as if they are native arrays, but if you made an object you interact with it using the get and set methods

store('ui').get('isVisible')
store('ui').set('isVisible', true)

Reading from and writing to the store

mobx-store has a simple lodash powered API.

  • Reading from the store is as simple as passing lodash methods to the store function. In order to pass methods to the store without actually executing them you can import from lodash/fp.

  • Writing to the store is done by calling the regular array methods as well the methods MobX exposes such as replace on the store object.

import { filter } from 'lodash/fp'
import mobxstore from 'mobx-store'

const store = mobxstore({ numbers: [] })

store('numbers') // read current value of store -- []
store('numbers').replace([1, 2, 3]) // write [1, 2, 3] to store
store('numbers').push(4) // push 4 into the store
store('numbers', filter((v) => v > 1)) // read [2, 3, 4] from store

You can also chain methods to create more complex queries by passing an array of functions to the store.

import { filter, map, sortBy, take, toUpper } from 'lodash/fp'
import mobxstore from 'mobx-store'

const store = mobxstore({ users: [] })

// Sort users by id and return an array of those with ids > 20
const result = store('users', [sortBy('id'), filter((x) => x.id > 20)])

If you save the result of one of your queries to a variable, you can continue working with the variable by using the chain API

// Take the top 3, and return an array of their names
store.chain(result, [take(3), map('name')])

// Filter again to get those with ids less than 100, take the top 2, and return an array of their names capitalized
store.chain(result, [filter((x) => x.id < 100), take(2), map((v) => toUpper(v.name))])

Scheduling reactions to state change

Reacting to state changes is done through the schedule API. You pass one to many arrays to the function. The first element of the array is your function, and the following elements are the arguments of your array.

For example mobx-store comes with an adapter for reading and writing to localstorage, which looks like this.

function read(source) {
  const data = localStorage.getItem(source)
  if (data) {
    return JSON.parse(data)
  }
  return {}
}

function write(dest, obj) {
  return localStorage.setItem(dest, JSON.stringify(obj))
}

export default { read, write }

Using this we can schedule writing to the localstorage whenever the store mutates.

import mobxstore from 'mobx-store'
import localstorage from 'mobx-store/localstorage'

// Create store initialized with value of localstorage at "info"
const store = mobxstore(localstorage.read('info'))

// schedule a reaction to changes to the state of the store
store.schedule([localstorage.write, 'info', store])

and you're done. Every change you make to this instance of mobx-store will persist to localstorage.

Undo and redo

To use undo and redo pass the name of a key in your store as a parameter. Make sure not to undo if you haven't altered the state of your store, or if you have called it too many times already, and likewise make sure not to call redo if you haven't yet called undo.

import mobxstore from 'mobx-store'

const store = mobxstore({ x: [] })

store.undo('x') // error

store('x').push(1)
store.undo('x') // undo push
store.redo('x') // redo push

store.redo('x') // error

You can avoid errors by using the functions canRedo and canUndo

if (store.canUndo('x')) {
  store.undo('x')
}
if (store.canRedo('x')) {
  store.redo('x')
}

You can limit the history of the undo by passing limitHistory to the store config

// Can only undo up to 10 times
const store = mobxstore({}, { limitHistory: 10 })

Limiting history should be usually be unnecessary as mobx-store doesn't store the entire object in history like Redux does, which potentially can take up a lot of memory. Instead, it only stores information about what changed, and only creates the new state when you call undo or redo.

Using with React

Read and apply the instructions you can find at mobx-react to make your components update when your store updates. The gist of it is that you just

import { observer } from 'mobx-react'

and wrap the component that is using your store in it.

Credit

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].