Last active
August 30, 2024 18:08
-
-
Save du5rte/dbd18a1a6dc72d866737a5e95ca1e663 to your computer and use it in GitHub Desktop.
Auto saving to localStorage with MobX
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import mobx from "mobx" | |
import store from "store" | |
export default function(_this) { | |
let firstRun = true | |
// will run on change | |
mobx.autorun(() => { | |
// on load check if there's an existing store on localStorage and extend the store | |
if (firstRun) { | |
const existingStore = store.get("store") | |
if (existingStore) { | |
mobx.extendObservable(_this, existingStore) | |
} | |
} | |
// from then on serialize and save to localStorage | |
store.set("store", mobx.toJS(_this)) | |
}) | |
firstRun = false | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import mobx, { computed, observable } from "mobx" | |
import autoSave from "./autoSave" | |
const initialTodoStore = { | |
todos: ["buy milk", "buy eggs"] | |
} | |
class TodoStore { | |
constructor() { | |
// set initial mock up examples | |
this.todos = initialTodoStore // or [] | |
// in the future it will over run it and save to store | |
autoSave(this) | |
} | |
@observable todos | |
@observable filter = "" | |
@computed get filteredTodos() { | |
const filter = new RegExp(this.filter, "i") | |
return this.todos.filter(todo => !this.filter || filter.test(todo)) | |
} | |
} | |
const todoStore = window.todoStore = new TodoStore | |
export default todoStore |
Using websockets seems to me a bit drastic solution. The reason is two browser windows/tabs of the same SPA, because the client wants to open several instances of components and be able to use it on several monitors.
In case anyone is interested what I did to solve my problem was to use the 'mobx-persist-store' library to write my store data to the localStorage.
Then (inside my store) I added a store event listener and update it every time I detect a change.
in mobxStore.ts
import { makePersistable, hydrateStore } from 'mobx-persist-store';
class Store {
// --- STORE STATE VARS ---
dashboard = {
isVisible: true,
};
constructor() {
makePersistable(this, { name: 'mobxStore',
properties: ['dashboard'],
storage: window.localStorage }).finally(() => {});
}
// --- SHOW/HIDE DASHBOARD ---
setDashboard(visible: boolean) {
this.dashboard.isVisible = visible;
}
}
const myStore = new Store();
window.addEventListener('storage', (e) => {
if (e.key === 'mobxStore') {
myStore.hydrateStore().catch(() => {});
}
});
export default myStore;
in a different window (but same domain http://localhost:3000/test )the component:
import React from 'react';
import { observer } from 'mobx-react';
import store from 'store/mobxStore';
const FakeComponent = () => {
const visible = store.dashboard.isVisible;
return (
<div>
{store.dashboard.isVisible ? <span>Dashboard visible</span> : <span>Dashboard Invisible</span>}
<br />
<div onClick={() => store.setDashboard(!visible)} >"Switch dashboard visibility"</div>
</div>
);
};
export default observer(FakeComponent);
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@hartum websockets maybe? idk why you wanna persist such data in localstorage but i guess hmr in react/next works like that only. they use websockets to listen if ui in one browser changed & update it everywhere i guess :)