I'm facing a stupid problem.
In a web app (my stack is vue + vuex + vue-router) I'm totally unable to synchronize my store state with the page the user is viewing.
When a user triggers the back or forward button, it triggers the same onpopstate event that gives absolutely no information about "direction" or the number of page. Only the array key in the state object seem to be barely workable (saving it when going to new places and then guessing where the user went onpopstate) but I don't even know where the "door" corresponding for "the key".
So from there I thought about manually tracking the history state key and guessing where the user has been but I guess it wouldn't be cross-compatible, and also it's heavy code to lift.
Here is my question: Am I missing some key element in the html5 API, how could I do (and keep code/logic minimalist)?
Thank you in advance!
EDIT: renamed the title and added info
EDIT2: vuex-router-sync is inappropriate since it only provides route info on vuex side and does not really sync router state and store state...to bad
P.S.: please don't c/p definitions, read carefully, think
onpopstate provides the state object in event.state correlating to the respective place in history of your application.
Write your application so that providing this state object encompasses the entire state of your application, regardless of time. I recommend you read about State pattern, and understand what "state" means, e.g.
the particular condition that someone or something is in at a specific time.
The implication I'm making is that you should not need to know the relative location in history your application is in, because event.state should be all your application needs in order to determine what to render.
Related
After researching the issue for a few days I've seem to have reached a dead end.
I'm dealing with, what I assumed, was a fairly common scenario: After user navigates to a certain page and makes some changes (content of an input field, scroll through grid data or even changing some editable cell values ), he navigates to different page. When user returns to original page, all of the changes must remain the same.
Now, that means that cursor in the aforementioned input field must be in the same place, scroll position in the grid and changed cell values, as well as any other changes user made, must be preserved.
Solutions like storing data in localStorage, using services or even custom reuse strategy will not work, because saving that amount of information contained in multiple sub components will be impossible.
Currently, I'm considering DOM manipulation, where rendered template will be moved to a container in parent component in onDestroy hook, and returned later in onInit. That, of course, is a hail Mary attempt and feels very unnatural.
I'm hoping someone had (and solved) this problem before because, like I've mentioned, it seams like fairly common use pattern.
There is not much option to do this in angular compared to React,
What I can recommend you is, store all the data in "environment" as object and when user routes back populate data from environment.
Usually I do this, when a component loads I store values in objects. When on destroy called all this objects goes to the environment under a one main object.
When oninit calls I am checking if object has values and restoring the page to where it was.
I think you are looking for Angular RouteReuseStrategy, where Angular can cache some routes state, without destroying the component state, so when ever the user visit the same route a cached view will be used,
RouteReuseStrategy Docs.
You can also check this medium article, implementing the required methods
Medium
for small amount data we can use services or localstorage as you mentioned
for large amount data we can go with
NgRx
https://dzone.com/articles/angular-app-state-management-with-ngrx
I use a service for this purpose, saving and restoring the state of the page from an object stored in the service but i haven't been able to figure out how persist the result of a user file upload where i am holding a user uploaded image
Pending file upload to cloud storage. Any ideas on solving this helpful as it seems like the cached file is cleared by angular navigation process
I am implementing an app where I can navigate to other users profiles. Obviously, entering to a profile have a cost for the database request, and also slows the user experience (having to wait for the db response to show the data).
Here comes AsyncStorage, a local database to cache objects and data from the DB. This API is deprecated, and some people is using redux with redux-persist instead...
In my app I am not using Redux, so to manage my purpose, I suppose I have to use AsyncStorage. But, what about React Context? Currently I have implemented a context provider "CurrentUserContext" which have a "VisitedUsers" map, in which I put the users data when I enter their profile (so to avoid unnecessary queries to the database, I only have to see if the data of that user is in this map). So, if a user want to see the most freshed data, he will have to refresh (the profile screen has a pull-to-refresh mechanism). Also, this context's life ends when the app is exited.
My question is: Is this a good option to use context for this kind of purposes? I have never seen anybody doing this... That is why I am doubtful.
From my point of view it's fine, since you really only have a short map (which gets done in a very short time) in a context that will last until the user closes the app or logs out.
Be careful, I ask it as a question, since I really don't know if this is a good practice. It should not be understood as "personal opinion".
Thank you.
I've been working with React for a little while, and after some time i started to ask myself, why not store every piece of data that my components need to share in localstorage instead of using Redux. Redux need so much boilerplate while localstorage is so simple. You can say that you cant storage object in localstorage but you can JSON.stringfy them, and on recovery just parse them back. So problaby there's something that i cant see properly about that, cause Redux is largely used and localstorage is normally used just to save data you dont wish to loss on refresh and things like that.
This question was on my head when I started developing react apps.
There are many reasons than below to use redux over localStorage.
but at least
Using Redux alongside react-redux is not only for store data. don't forget that changing in a state will reRender All components that listen to that state. and that is really what react-redux does.
stringify/parse from localStorage will make your app (on high-scale) slower and also will not sync all components while changing state.
Personal Recommendation After more than 4 years of developing React Apps, use REDUX with easy API like redux-toolkit or rematch
Redux and localStorage have different use cases actually. Redux you'll use to manage your application state across multiple components.
Local Storage you'll use to persist properties in the browser for later usage. The problem is that any change on your localStorage won't reflect on your application. You'll have to do it manually.
The purpose of react-redux is to allow other components to connect to state and then react on changes. You are loosing the whole scope of using react-redux/context api.
The answer is in your question, yes local storage is only used for storing data in the browser while redux and context api solve some different problem. It separates your data layer from your view to easily manage your data state. If the app is not really big then you should consider going with Context API.
You can read this article for more info.
Note, stringifying and parsing itself is a pretty heavy operations for larger datasets.
It's probably OK to use localstorage instead of Redux. It's possible to have changes in localstorage have immediate effect on subscribed react components.
The people at marmelab who built react-admin transitioned from using redux to what they call The Store.
React-admin contains a global, synchronous, persistent store for
storing user preferences. Think of the Store as a key-value database
that persists between page loads.
The store uses the browser local storage (or a memory storage when
localStorage isn’t available). The store is emptied when the user logs
out.
When using react-admin changes in localstorage have immediate effect on subscribed react components. Checkout the readme and try the demo. Do some fiddling with data in localstorage manually, and see how react components rerender. I was amazed when I saw that for the first time.
I think it's ok. It depends on your requirement. In our situation, we need to split a big project into several small projects, whether use Redux or Mobx both cause problem very difficult, so we totally remove Redux and Mobx, just use LocalStorage to save all states. We know it will be slow and cannot rerender when state changes, but we want to accept it, and even add a Refresh button on some page if need to get state from local storage. So the answer is: it's ok to totally remove Redux, just see if you want to accept it or not.
Why use Redux instead of localStorage:
Disk space: You will probably not be deleting data from local storage every time the user quits your website. (you could with onbeforeonunload event enter link description here but it doesn't look like a good pracitce).
Security: If you are saving user's data, you would have to be careful on not mixing users data saved on localStorage.
Why not use Redux instead of localStorage:
"update the state": The truth is that you can listen to changes on localStorage and then change the state. So, I think, this is not a good reason. For example:
window.addEventListener('storage', (event) => { setState("changed")});
Simplicity: as Zhang Buzz, redux can be a pain.
Each case is different and you'll needs to weight the pros and cons to make a good decision.
I have an app that uses a sync API to get its data, and requires to store all the data locally.
The data set itself is very large, and I am reluctant to store it in memory, since it can contains thousands of records. Since I don't think the actual data structure is relevant, let's assume I am building an email client that needs to be accessible offline, and that I want my storage mechanism to be IndexedDB (which is async).
I know that a simple solution would be to not have the data structure as part of my state object and only populate the state with the required data (eg - store email content on state when EMAIL_OPEN action is triggered). This is quite simple, especially with redux-thunk.
However, this would mean I need to compromise 2 things:
The user data is no longer part of the "application state", although in truth it is. Since the sync behavior is complex, and removing it from the app state machine will hurt the elegance of the redux concepts (the way I understand them)
I really like the redux architecture and would like all of my logic to go through it, not just the view state.
Are there any best-practices on how to use redux with a not-in-memory state properties? The thing I find hardest to wrap my head around is that redux relies on synchronous APIs, and so I cannot replace my state object with an async state object (unless I remove redux completely and replace it with my own, async implementation and connector).
I couldn't find an answer using Google, but if there are already good resources on the subject I would love to be pointed out as well.
UPDATE:
Question was answered but wanted to give a better explantation into how I implemented it, in case someone runs into it:
The main idea is to maintain change lists of both client and server using simply redux reducers, and use a connector to listen to these change lists to update IDB, and also to update the server with client changes:
When client makes changes, use reducers to update client change list.
When server sends updates, use reducers to update server change list.
A connector listens to store, and on state change updates IDB. Also maintain internal list of items that were modified.
When updating the server, use list of modified items to pull delta from IDB and send to server.
When accessing the data, use normal actions to pull from IDB (eg using redux-thunk)
The only caveat with this approach is that since the real state is stored in IDB, so we do lose some of the value of having one state object (and also harder to rewind/fast-forward state)
I think your first hunch is correct. If(!) you can't store everything in the store, you have to store less in the store. But I believe I can make that solution sound much better:
IndexedDB just becomes another endpoint, much like any server API you consume. When you fetch data from the server, you forward it to IndexedDB, from where your store is then populated. The store gets just what it needs and caches it as long as it doesn't get too big or stale.
It's really not different than, say, Facebook consuming their API. There's never all the data for a user in the store. References are implemented with IDs and these are loaded when required.
You can keep all your logic in redux. Just create actions as usual for user actions and data changes, get the data you need and process it. The interface is still completely defined by the user data because you always have the information in the store that is needed to GET TO the rest of it when needed. It's just somewhat condensed, i. e. you only save the total number of messages or the IDs of a mailbox until the user navigates to it.
The StateManager in Ember.js isn't that well documented yet, so I've got some questions regarding its usage.
Should one strive to call .goToState only from within the state manager?
I sometimes find myself mirroring methods in the state manager on the view, e.g. save: -> StateManager.send("save"). Does that make sense or am I missing something?
Should all modification of models (generally) go through the state manager?
If one view has different states, should that be modeled using a ViewState with child states, or should I use computed properties and view properties to hold that information only in the view (without the state manager knowing of the views internal state)?*
*One example could be a three-step form, where the same template is used for all states but different areas are shown/hidden in the three steps.
Github reference: https://github.com/emberjs/ember.js/tree/master/packages/ember-states/lib
Should one strive to call .goToState only from within the state
manager?
Probably. I don't know this for certain, but it seems to me that because the state manager knows what state you're in, it's the place to enforce legal state transitions. If you called .goToState from outside the state manager, you're doing it without really knowing what state you're in, and while that's sometimes OK (maybe it's a state you really can reach from any other state) it's not a great habit to be in.
I sometimes find myself mirroring methods in the state
manager on the view, e.g. save: -> StateManager.send("save"). Does
that make sense or am I missing something?
I like what pangratz has to say about this.
Should all modification of
models (generally) go through the state manager?
The way I use statecharts, no. I've seen some people using statecharts as pretty much a complete replacement for the controller layer, however, and if that's how you're working, then yes, it should go through the state manager. The pattern is to avoid direct manipulation of models from views; whether it's a controller layer or a state manager in between seems like a moot point to me.
The way I use state charts, however, the state manager is made to manage the state of the application. It can play traffic manager for the modification of models if that modification will change the state of the application (e.g. if there's a progress indicator while an update completes), but it seems to me that model updates aren't part of its mandate; they belong to controllers.
If one view has
different states, should that be modeled using a ViewState with child
states, or should I use computed properties and view properties to
hold that information only in the view (without the state manager
knowing of the views internal state)?
I think the state manager needs to know (or ought to know) the view's internal state.
Out of curiosity, are you coming from a web development background, or a desktop/mobile app development background? I came from web development, and state charts were a new concept for me. I found it very useful to read the canonical State Chart paper by David Harel ('ware PDF!). It's surprisingly readable for an academic paper and lays out the basic state chart concept most of the SproutCore/Ember world has been using since late 2010 (i.e. it's what Michael Cohen had in mind when he wrote Ki.)
Regarding your point 2:
I sometimes find myself mirroring methods in the state manager on the view, e.g. save: -> StateManager.send("save"). Does that make sense or am I missing something?
You could use the action helper in your Handlebars template and set your StateManager as target
{{action "send" target="App.stateManager"}}
And the the send event is send to your App.stateManager.