Skip to content

Instantly share code, notes, and snippets.

@benjick
Created June 15, 2017 11:09
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save benjick/c48dd2db575e79c7b0b1043de4556ebc to your computer and use it in GitHub Desktop.
Save benjick/c48dd2db575e79c7b0b1043de4556ebc to your computer and use it in GitHub Desktop.
mobx-state-tree persist PoC

Took some inspiration from https://github.com/pinqy520/mobx-persist to try this out

Usage:

import { types } from 'mobx-state-tree';
import moment from 'moment';
import { AsyncStorage } from 'react-native';
import { persist } from './persist';

const Store = types.model('Store', {
  date: '1989-06-01',
  hydrated: false,
  get age() {
    const birthday = moment(this.date);
    return moment().diff(birthday, 'years');
  },
}, {
  setDate(date) {
    this.date = date;
  },
  afterHydration() {
    // This lifecycle is called after the store is hydrated
    this.hydrated = true;
    console.log('I feel refreshed!');
  },
});

const store = Store.create();

persist('@MyStoreKey', store, {
  storage: AsyncStorage, // AsyncStorage for React-Native, localStorage for web
  jsonify: true, // Set to true if using AsyncStorage
}, {
  date: true, // which keys to persist
});

export default store;
/* globals localStorage */
import { onSnapshot, applySnapshot } from 'mobx-state-tree';
import Storage from './storage';
export const persist = (name, store, options, schema = {}) => {
let hydrated = false;
let storage = options.storage;
if (typeof localStorage !== 'undefined' && localStorage === storage) {
storage = Storage;
}
onSnapshot(store, (_snapshot) => {
if (!hydrated) {
return;
}
const snapshot = { ..._snapshot };
Object.keys(snapshot).forEach((key) => {
if (!schema[key]) {
delete snapshot[key];
}
});
const data = !options.jsonify ? snapshot : JSON.stringify(snapshot);
storage.setItem(name, data);
});
storage.getItem(name)
.then((data) => {
if (data) {
const snapshot = !options.jsonify ? data : JSON.parse(data);
applySnapshot(store, snapshot);
if (store.afterHydration && typeof store.afterHydration === 'function') {
store.afterHydration();
}
hydrated = true;
}
});
};
/* globals window */
// Borrowed from https://raw.githubusercontent.com/pinqy520/mobx-persist/8d68e5b50575feec8a44cd0db7313d08d96d2255/lib/storage.js
export function clear() {
return new Promise((resolve, reject) => {
try {
window.localStorage.clear();
resolve(null);
} catch (err) {
reject(err);
}
});
}
export function getItem(key) {
return new Promise((resolve, reject) => {
try {
const value = window.localStorage.getItem(key);
resolve(value);
} catch (err) {
reject(err);
}
});
}
export function removeItem(key) {
return new Promise((resolve, reject) => {
try {
window.localStorage.removeItem(key);
resolve(null);
} catch (err) {
reject(err);
}
});
}
export function setItem(key, value) {
return new Promise((resolve, reject) => {
try {
window.localStorage.setItem(key, value);
resolve(null);
} catch (err) {
reject(err);
}
});
}
@ccfiel
Copy link

ccfiel commented Apr 18, 2018

have you used it in production? :)

@agilgur5
Copy link

agilgur5 commented May 24, 2019

@ccfiel I used it in production and it mostly worked, but required one change, moving the hydrated = true statement to outside of the if (data) block (otherwise hydrated will never be set to true because there is no data initially persisted).

@agilgur5
Copy link

agilgur5 commented May 24, 2019

I recently created mst-persist with inspiration from this gist, mobx-persist, and redux-persist as a standalone library to handle persistence with MST. Check it out and report any issues or contribute! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment