acrazing / mobx-sync Goto Github PK
View Code? Open in Web Editor NEWA library to persist mobx store automatically
License: MIT License
A library to persist mobx store automatically
License: MIT License
I am new to this library, but my project is based without decorators because create-react-app does not support them. And the workarounds for supporting decorators could be detrimental to performance/stability.
How do I use this without decorators?
I just wanted to reach out and check if this project is still being (or will be) maintained.
I quite like it, but have noticed a few issues lately with compatibility of dependencies. The biggest being that it seems this library is incompatible with mobx 6. Also it seems the library only supports the deprecated version of the AsyncStorage
library in React Native (https://reactnative.dev/docs/asyncstorage).
Thanks for all your work here!
I found that mobx-sync requires mobx in dependencies section. In my case I use mobx 4.8 but mobx-sync installed 5.8 (because of "mobx": "*"). So I cannot use it with IE11.
I think that mobx should be declared in peerDependencies section something like this:
"peerDependencies": {
"mobx": "^4.3.1 || ^5.0.0"
},
This seems like a bug, perhaps from a previous version of mobx?
Line 71 in f10db40
Hi, thanks for the lib, really liking it so far :)
However, I'm not able to make the @ignore
decorator work. All of the fields are persisted correctly (and the observer is reacting correctly on updates).
This is a snippet of my store class:
class Store {
@ignore
@observable
movieData: TMovies | null = null;
... other observable fields
}
I've tried the @ignore.ssr
and @ignore.ssrOnly
variations but the movieData
is always persisted.
As extra context, I'm using this with mobx-react
like:
function createStore() {
return new Store();
}
export const StoreProvider: FC = ({children}) => {
const store = useLocalStore(createStore);
const [storeReady, setStoreReady] = useState(false);
const trunk = new AsyncTrunk(store, {
storage: AsyncStorage,
storageKey: 'key2',
});
useEffect(() => {
trunk.init().then(() => {
setStoreReady(true);
});
}, []);
return (
<Context.Provider value={store}>
{storeReady ? (
children
) : (
<Loader />
)}
</Context.Provider>
);
};
Am I doing something wrong?
Is there an easy way to implement localforage into this tool?
I couldn't import the new decorators in v0.6.0 in my app using:
import { format, date, regexp } from 'mobx-sync
I believe you have missed exporting them in index.ts
.
I added this line to the file, which fixed the issue:
export { format,date,regexp } from './format';
Just found this! I was writing my own mobx persistent lib, but this one will save me some time.
If the data isn't locally found, it will keep the initial value?
Also, if there is an error during the save/load, will there be any Error throw?
I have something like this:
import { observable, computed } from "mobx";
export class EnvironmentModel {
@observable public id: string;
@observable public name: string;
constructor(id: string, name: string) {
this.id = id;
this.name = name;
}
@computed get initials() {
let tokens = this.name.split(" ");
let res = "blah";
if (tokens.length === 1) {
res = tokens[0].slice(0, 2);
} else {
res = tokens[0][0] + tokens[1][0];
}
return res;
}
}
import { EnvironmentModel } from "../model";
import { RootStore } from "./Root.store";
import { observable, action } from "mobx";
import { ignore } from "mobx-sync";
let localEnv = new EnvironmentModel("local", "Local Environment");
export class EnvironmentStore {
@ignore root: RootStore;
@observable.shallow public current: EnvironmentModel = localEnv;
@observable.shallow
public environments: EnvironmentModel[] = observable.array([localEnv]);
constructor(root: RootStore) {
this.root = root;
}
// TODO: Placeholder function
@action
public loginToEnvironment(envName: string, email: string, password: string) {
let newEnv = new EnvironmentModel(envName, envName);
this.environments.push(newEnv);
this.switchEnvironment(newEnv.id);
}
@action switchEnvironment(envId: string) {
let env = this.environments.find(e => e.id === envId);
if (!env) {
// do something a toast or w/e
return;
}
this.current = env;
}
}
Everything works fine the first time when the objects are created on runtime, but once my store is rehydrated upon application load, the computed initials is no longer working and returns undefined.
Any idea why this might be happening? Am I doing something wrong?
Hey im getting a bunch of errors when trying to use this in my Typescript project.
Im using the version from npm yarn add mobx-sync
but it tells me that its missing the type definitions for the module?
I also get runtime errors saying that there are multiple versions of mobx running at once? Perhaps the mobx dependency needs to be peer?
When I open site in a new tab, data get from default @observable variables values, not from SessionStorage.
I'm using new create-react-app app with typescript. Everything was installed correctly.
Error:
Failed to compile.
/Users/alder/node_modules/mobx-sync/lib/async.mjs
Can't import the named export '__awaiter' from non EcmaScript module (only default export is available)
Code:
import { AsyncTrunk } from 'mobx-sync/lib/async'
import { rootStore } from './stores';
const trunk = new AsyncTrunk(rootStore, { storage: localStorage })
trunk.init().then(() => {
ReactDOM.render(<App />, document.getElementById('root'));
})
packages.json:
"dependencies": {
"@material-ui/core": "^4.0.0-alpha.8",
"axios": "^0.19.0-beta.1",
"crypto-ts": "^1.0.2",
"formik": "^1.5.4",
"history": "^4.9.0",
"lodash": "^4.17.11",
"mobx": "^5.9.4",
"mobx-react": "beta",
"mobx-state-router": "^4.0.5",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-input-mask": "^2.0.4",
"react-scripts": "^3.0.0",
"styled-components": "^4.2.0",
"yup": "^0.27.0"
},
"devDependencies": {
"@types/history": "^4.7.2",
"@types/lodash": "^4.14.123",
"@types/material-ui": "^0.21.6",
"@types/react": "^16.8.14",
"@types/react-dom": "^16.8.4",
"@types/react-input-mask": "^2.0.1",
"@types/styled-components": "^4.1.14",
"@types/yup": "^0.26.12",
"@typescript-eslint/eslint-plugin": "^1.7.0",
"eslint-config-prettier": "^4.2.0",
"eslint-config-typescript": "^2.0.0",
"eslint-plugin-react": "^7.12.4",
"husky": "^2.1.0",
"lint-staged": "^8.1.5",
"prettier": "^1.17.0",
"typescript": "^3.4.5"
},
https://medium.com/@joking.young/mobx-sync-a-better-library-to-persist-your-mobx-stores-1dafb8e5f00c
The library mobx-sync is a prefect choice to do this job, which is wrote by myself.
Does this library work with Mobx State Tree, if so could you give some examples or some pointers in the right direction
I had issues on mobx-persist
and I saw that this package would fit my needs. However, following the tutorial.. I am already getting an error I am stuck at:
Uncaught TypeError: mobx_sync__WEBPACK_IMPORTED_MODULE_9__.AsyncTrunk is not a constructor
at Module.eval (main.tsx?5177:15)
at eval (main.tsx:67)
at Module../main.tsx (app.856980a5f3b10010e12e.js:625)
at webpack_require (856980a5f3b10010e12e.js:785)
at fn (856980a5f3b10010e12e.js:151)
at Object.0 (app.856980a5f3b10010e12e.js:638)
at webpack_require (856980a5f3b10010e12e.js:785)
at checkDeferredModules (856980a5f3b10010e12e.js:46)
at Array.webpackJsonpCallback [as push] (856980a5f3b10010e12e.js:33)
at app.856980a5f3b10010e12e.js:1
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {Provider} from 'mobx-react';
import {RootStores} from 'app/stores';
import {App} from 'app';
import {createBrowserHistory} from "history";
import {AsyncTrunk} from "mobx-sync";
// prepare MobX stores
const history = createBrowserHistory();
const stores = new RootStores(history).getStoresInstances();
const trunk = new AsyncTrunk(stores, {
/**
* @desc custom storage: built in storage is supported
* - localStorage
* - sessionStorage
* - ReactNative.AsyncStorage
*/
storage: localStorage as any,
/**
* @desc custom storage key, the default is `__mobx_sync__`
*/
storageKey: '__persist_mobx_stores__',
});
trunk.init().then(() => {
// render react DOM
console.log("// render react DOM");
ReactDOM.render(
<Provider {...stores}>
<App history={history}/>
</Provider>,
document.getElementById('root')
);
});
I am attempting to utilize your package to persist multiple mobx
stores as per the example here and have my stores setup in a similar fashion to this:
/* RootStore.js */
import {UserStore, TodoStore } from './index.js'
import { AsyncTrunk } from 'mobx-sync';
import AsyncStorage from '@react-native-community/async-storage';
class RootStore {
constructor() {
this.userStore = new UserStore()
this.todoStore = new TodoStore()
}
}
const rootStore = new RootStore();
const trunk = new AsyncTrunk(rootStore, {
storageKey: 'myAppStore',
storage: AsyncStorage,
onError: error => console.error('TRUNK ERROR', error)
});
export { rootStore, RootStore, trunk };
/* UserStore.js */
import {rootStore} from './RootStore.js'
class UserStore {
constructor(rootStore) {
this.rootStore = rootStore
}
getTodos(user) {
// access todoStore through the root store
return this.rootStore.todoStore.todos.filter((todo) => todo.author === user)
}
}
/* TodoStore.js */
import {rootStore} from './RootStore.js'
class TodoStore {
@observable todos = []
constructor(rootStore) {
this.rootStore = rootStore
}
}
I then call the following function to hydrate the stores on app start:
const initApp = () => {
trunk.init().then(() => {
console.log('hydrate done', rootStore.userStore); //always undefined
}
}
rootStore.userStore
is always undefined, how can I persist multiple stores using this package?
Thanks.
mobx: 5.15.4
react-native: 0.61.5
mobx-sync: 3.0.0
@react-native-community/async-storage: 1.11.0
Local storage is not unlimited, so persistence can sometimes result in failure. Is there any way to detect and respond to this happening when using mobx-sync?
An example of an error that can show up on the console log,
cycle reference occurred > Array [] sync.js:30
Both work on the parent store:
export class TodoListStore {
@date date2:any
@format((value) => new moment(value)) date:any
@observable todos: TodoItem[] = []
}
But do not work on the sub-classes.
export class TodoItem {
@ignore id: string;
@date date2:any
@format((value) => new moment(value)) date:any
}
@ignore
works on the subclass - the serialise logic is good, but the de-serialise logic is broken.
When I debug parse-store.ts
, the todos observable hits this line only and does not recursively then call parseStore()
on the nested object
else if (mobx_1.isObservableArray(storeValue)) {
// mobx array
store[key] = mobx_1.observable.array(dataValue);
}
Maybe this gives a clue?
Is it possible to achieve the inverted behaviour when only specifically decorated properties will be synced with the storage, but all others will not sync by default?
there seems to be absolutely no documentation for this lib due to this
Often on a dev server, I will want to refresh the page. However, using this library, refreshes can take 10-15 seconds. Is this normal, or is it specific to my setup?
Hi, thanks for the lib!
Any guidance on how to rehydrate an object property of type JS Date or a custom type e.g. a Moment date. They persist fine to a string value as they implement the native JS serialisation interface i.e. toJSON()
. But just need a way to run when re-hyrdating the save state to call a custom function with code like new Moment(value).
I saw this todo comment in the source code about this requirement.
The @serlizer
lib has an @date
decorator and a custom decorator.
in my code, i import like this:
import {AsyncTrunk} from "mobx-sync";
results in:
ERROR in ./node_modules/mobx-sync/lib/index.mjs 10:0-37
Can't reexport the named export 'AsyncTrunk' from non EcmaScript module (only default export is available)
@ ./src/main.tsx
@ multi (webpack)-dev-server/client?http://localhost:8082 ./src/main.tsx
ERROR in ./node_modules/mobx-sync/lib/index.mjs 13:0-35
Can't reexport the named export 'SyncTrunk' from non EcmaScript module (only default export is available)
@ ./src/main.tsx
@ multi (webpack)-dev-server/client?http://localhost:8082 ./src/main.tsx
ERROR in ./node_modules/mobx-sync/lib/index.mjs 14:0-34
Can't reexport the named export 'config' from non EcmaScript module (only default export is available)
@ ./src/main.tsx
@ multi (webpack)-dev-server/client?http://localhost:8082 ./src/main.tsx
ERROR in ./node_modules/mobx-sync/lib/index.mjs 11:0-70
Can't reexport the named export 'date' from non EcmaScript module (only default export is available)
@ ./src/main.tsx
@ multi (webpack)-dev-server/client?http://localhost:8082 ./src/main.tsx
ERROR in ./node_modules/mobx-sync/lib/index.mjs 11:0-70
Can't reexport the named export 'format' from non EcmaScript module (only default export is available)
@ ./src/main.tsx
@ multi (webpack)-dev-server/client?http://localhost:8082 ./src/main.tsx
Storing objects is working fine but when it's an array it's not persisted.
@observable list = [{a: '1', b: '2'}];
I have a simple interface
interface Todo {
title: string;
deadline: Date;
}
And it persists correctly.
But is there a way for rehydrating Date object without rewriting this to class? I know, that this would be simple class, it's just I don't want to use one when it's not needed.
this code has no releases on github and no changelog..
Getting the following issue:
Multiple MobX instances in your application
mobxjs/mobx#1082 (comment)
I think the problem can be solved if mobx is not used as a direct dependencies in this project but instead used in peerDependencies and devDependencies from the package.json
If I use mobx-sync with forage, both have their version control, which one should I use?
I'm using mobx-sync in a React application to persist state for an offline mode. One issue I am facing is that when persisting a store that has an array of objects where those objects have actions for modifying their state, when initialized from storage the JS objects in the store know nothing about the methods that were on the object when it was first added. I can see what, and why the problem is occurring, but at a loss to what would be the best way to address it.
So if I have a ProfileStore that contains a set of Options and ProfileStore has actions to add an option, that is fine. But if Option has an action to update state, after loading that store and it's Options, the loaded Option throws "... is not a function" exceptions. Obviously the array of Option state is not "typed" to the Option class that is defined. I'm left wondering if there is a way to deserialize them in a way that is recognized as that type, or a best practice to alter the structure so that the actions don't rely on the state. I would like options to live under a profile store rather than trying to juggle separate stores for loosely coupled objects.
This looks to be related to issue #14, but running a React application with mobx-sync results in import errors. Even the most basic example results in the error:
Can't import the named export '__assign' from non EcmaScript module (only default export is available)
I can see from issue #14 that the suggested fix is a webpack change, however with react-create-app this would require ejecting the configuration to try and tweak the webpack settings, which I would like to avoid since it isn't reversible. Is there a way that I can rebuild the mobx-sync package to be ECMAScript compatible, or otherwise reference it in a way that the module shaker will understand?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.