I want something like document.referrer. But since I'm building a single page app, with backbone and pushstate, the value is "".
How can I get something like history.prevState().url.
EDIT: I do not need the event. I want to access info of the previous state anytime/anywhere I want.
Perhaps you could simply store the last state in the new state object.
history.pushState({
lastState: 'some state'
}, '', 'newpage.html');
console.log(history.state.lastState); //some state
If you are building a single-page application, even if there are no standardization on how the state transition is initiated you could probably manage to intercept all of them by listening to the popstate and the onhashchange events.
You could then just push every states encountered in an array and store a serialized version of it in the localStorage. That would allow you retrieving any previous states. However, this collection will grow so you would have to make sure that you control it's size. You could also simply keep the last state instead of all of them.
However, it would definitely be better to establish a standard across modules. Not only it would make accessing the previous state easier, but it would also be easier to maintain and more flexible in terms of future changes.
Related
I use LocalStorage to persist some content of my Vue3 app. Today, I just write to LocalStorage any changes in the content I want to preserve and read from that contact in specific cases (an interval, or some other trigger).
The last part is not optimal because I need to have complex logic about how to make the LocalStorage → app update (LocalStorage can be updated by "something else", and this update should reflected in the app)
The solution would be to bind the content of LocalStorage with a reactive variable, which would natively bring two advantages:
any change in the variable or LocalStorage is reflected in the other one
changes are naturally persistent
Question 1: Is this something that is possible (Vue3 and a modern browser)?
Question 2: I recently heard about FileSystem which seems to be a possible alternative to LocalStorage, but I do not know it enough to assess whether it could be more suited to solve my problem?
Note: there is a similar question (How to make data from localStorage reactive in Vue js) but it does not cover Vue3 and the possible use of FileSystem. The answer is basically "it is not possible natively. I will mark it as a duplicate if this is still the case.
If I understand your question right, if you are updating localStorage at one place, it should also update on other pages.
I never tried this, but I can think of two approaches.
where you can listen to storage event https://developer.mozilla.org/en-US/docs/Web/API/Window/storage_event
this has some limitations, please check.
Create an Event and attach it to the window & whenever you are updating localStorage dispatch the custom event and on listening to the custom event, fetch the data from localStorage.
If I have a class with a bunch of properties, it seems like a hassle to put the properties that I modify inside (for example) this.state.myProp1 instead of this.myProp1. and then I need to make a copy of whatever property it is before I send it off to setState (because I can't mutate it directly). Like an array of objects for example.
At some point I display some of these properties so that means that I need to hold all my class properties inside this state, and then keep track of what I need to refresh, instead of refreshing the whole thing.
I almost prefer to use this.forceUpdate() instead and have my render() refer to class properties directly. Why does react "make" people use this.state and setState. Is it for performance reasons?
setState() enqueues changes to the component state and tells React that this component and its children need to be re-rendered with the updated state. This is the primary method you use to update the user interface in response to event handlers and server responses.
So basically setState is there to tell react when to re-render. Also setState behaves asynchronously, and updates the state only when necessary. So if you call setState multiple times immediately it will update only on the last one so as to minimize the number of re-renders and be less taxing on the browser. If there was no setState and react re-rendered every time the data changed, the browser experience would be terrible.
You don't have to use React this.state and setState if you don't want to. You can always use redux or mobx to manage the state.
Never mutate this.state directly, as calling setState() afterwards may replace the mutation you made.
And yeah, that's why you've to make a copy of whatever property it is before I send it off to setState
IMHO, component state is an elegant concept for some special case. for example when you want to monitor the content change of a text input on live, that is, not after hit save or submit button. under such situation, a component state would be ideal place to store the temporary input and you will not get overhead to use redux action to respond on the every incomplete input. it is just like a buffer to provide performance improvement.
1. Reasons behind setState
The main reason for having to use setState is its asynchronous execution, from the react docs:
React intentionally “waits” until all components call setState() in their event handlers before starting to re-render. This boosts performance by avoiding unnecessary re-renders.
If the state object was updated synchronously it would cause consistency issues, since props are not updated until the parent component is re-rendered, so, mutating this.state directly would lead to inconsistency between props and state.
For further reference, you can check this this Github thread.
2. Reasons behind this.state
The main advantage of the state object is its immutability which couldn't be accomplished with component properties, also there is the separation of responsibility between props and state, which is way easier to handle and update individually.
Why does react "make" people use this.state and setState. Is it for performance reasons?
That's a good question - the existing answer from J. Pichardo is quite correct but I wanted to address the why in a little more depth - as opposed to what or how.
Really a better question is - why does React exist? According to this article
React’s one-way data flow makes things much simpler, more predictable, and less bug-prone. One way data flow greatly simplifies your thinking about state because no view can ever mutate the state directly. Views can only send actions up to the global state store.
Really theres a whole bunch of reasons why React has it's place as a useful UI library. But in regards to your question - uni-directional data flow - this is the main reason.
relational UIs get complex. When an app has to consume, display and update even just a modest amount of relational data and have that information displayed across multiple elements, things can get messy fast.
Using state and props the way that React does allows one to differentiate and guarantee whether a piece of the UI will just receive data to display or whether it might change it too.
If you store that data just in a random key you have no real way of knowing whether the value is changed and what changed it. By separating out your state from your component in this way, it decouples the data from the element and makes it much easier to share data between elements and also change that data in different ways.
according to this article on coupled object interfaces a tightly coupled entity is bad because:
A tightly Coupled Object is an object that needs to know about other objects and are usually highly dependent on each other's interfaces. When we change one object in a tightly coupled application often it requires changes to a number of other objects. There is no problem in a small application we can easily identify the change. But in the case of a large applications these inter-dependencies are not always known by every consumer or other developers or there is many chance of future changes.
This very much is applicable in UI development also. In my opinion this is why not setting state is going to cause you some pain later on.
I have a rather complex web page with various tabs, forms, radio buttons, drop downs, etc. It's all bound using Knockout.js to a very complex JavaScript object that was loaded via an AJAX call. Of course the user can muck with stuff to their heart's content, at which point they hit a Save button to persist all their changes back to the server.
I'm in the process of coming up with a good design to track exactly what was changed on the page so I can implement saving. So, I've come up with a few possible implementations.
Option 1) Just send everything back and let the server sort it out: With this method, I'd let Knockout just update the data source. The Save button would call .toJS() and send that data back to the server. Pros: It's super easy, and takes very little work on the client. Cons: The server doesn't really know what changed and has to either load the data from the database to compare, or just save all the fields again. These fields come from multiple tables and have complex relations. It also treats the entire document as a single atomic unit. If someone else changed Field A and you changed field B, one user is going to lose their change.
Option 2) Use JavaScript to compare the original data and the current data: Using this technique, when the user clicks on the Save button, I would systematically compare the original data and current data and generate a graph of changes. Pros: This would ideally result in a compact graph of exactly what the user changed, and could even no-op if nothing was changed. Cons: The data I'm binding to is complex. It consists of strings, arrays, objects, arrays of objects, arrays of objects with other objects, etc. Looking for changes would be a rather complex nested loop.
Option 3) Track changes as they are being made in the UI: I would have to observe changes as they happen, and keep a delta as UI elements were changed. The Save button would simply send that change graph to the server if it had any pending changes. Pros: No need to compare two huge JavaScript objects looking for changes, but still has all the benefits of option 2. Cons: Knockout doesn't appear to have a standard way to listen to all changes using a single event handler. I believe I would have to resort to binding to all the UI elements, or creating custom bindingHandlers in Knockout to implement this real-time change tracking.
My Question:
My question is mostly for Knockout.js experts. Is there a standard approach, or recommended guidelines to solving this obviously common scenario? Is sending back all the data, even stuff that hasn't changed, a common design? Or are people implementing custom change trackers? Does Knockout provide any sort of framework that eases this requirement?
Update: Found this thing, not sure if it could be useful or if anyone has any feedback on it.
If it's a question of enabling/disabling the Save button, allowing the user to navigate "from" that page/state, then you can check with the https://github.com/CodeSeven/kolite
check the knockout.dirtyFlag.js
Hope this helps.
Edit: remember that you should "never" trust the data coming from the "UI". The real comparison and validation, ultimately goes in your "controlled" environment within the server.
What I would probably do is take option 2 - the comparison itself can be as simple as stringifying the JS object and comparing it with a cached version of itself.
A few other options are discussed here.
P.S. Maybe ko.mapping can help you manage this monster of a JS object?
I wrote a change tracker extension for knockout that Pete Smith greatly expanded on...
Take a look here:
https://roysvork.wordpress.com/2014/01/12/tracking-changes-to-complex-viewmodels-with-knockout-js/
It works on the principle of extending the observable to track initial state vs. changes the user has made on the client. I think this works really great and can give users real-time feedback to know what they've modified. In practice, we actually implement a save panel that shows all pending changes and even lets them undo individual changes, all by using the change tracker's reusable capability.
ko.extenders.trackChange = function (target, track) {
if (track) {
target.isDirty = ko.observable(false);
target.originalValue = target();
target.subscribe(function (newValue) {
// use != not !== so numbers will equate naturally
target.isDirty(newValue != target.originalValue);
});
}
return target;
};
I often use data-attributes to store configuration that I can't semantically markup so that the JS will behave in a certain way for those elements. Now this is fine for pages where the server renders them (dutifully filling out the data-attributes).
However, I've seen examples where the javascript writes data-attributes to save bits of data it may need later. For example, posting some data to the server. If it fails to send then storing the data in a data-attribute and providing a retry button. When the retry button is clicked it finds the appropriate data-attribute and tries again.
To me this feels dirty and expensive as I have to delve into the DOM to then dig this bit of data out, but it's also very easy for me to do.
I can see 2 alternative approaches:
One would be to either take advantage of the scoping of an anonymous Javascript function to keep a handle on the original bit of data, although this may not be possible and could perhaps lead to too much "magic".
Two, keep an object lying around that keeps a track of these things. Instead of asking the DOM for the contents of a certain data-attribute I just query my object.
I guess my assumptions are that the DOM should not be used to store arbitrary bits of state, and instead we should use simpler objects that have a single purpose. On top of that I assume that accessing the DOM is more expensive than a simpler, but specific object to keep track of things.
What do other people think with regards to, performance, clarity and ease of execution?
Your assumptions are very good! Although it's allowed and perfectly valid, it's not a good practice to store data in the DOM. Sure, it's fine if you only have one input field, but, but as the application grows, you end up with a jumbled mess of data everywhere...and as you mentioned, the DOM is SLOW.
The bigger the app, the more essential it is to separate your interests:
DOM Events -> trigger JS functions -> access Data (JS object, JS API, or AJAX API) -> process results (API call or DOM Change)
I'm a big fan of creating an API to access JS data, so you can also trigger new events upon add, delete, get, change.
1) Which JavaScript hashchange/history library/method should I use for my JavaScript application?
2) And how do I achieve these 3 things using that method?
A) When the page loads I want to parse the url hash/parameters and set the initial application state.
Specifically, my application consists of a Backbone Collection with two models which has attributes such as selectedCountry, selectedYear etc.
(I don't think I can use the Backbone.Router as this is a very customized visualization app with complex states?)
B) I want to set up a hashchange listener or similar that lets me update the app state correspondigly
C) On Backbone Collection change events I'd like to update the url. Important: I want to remove the hashchange listener temporarily while doing this so that there is no feedback loop.
Note:
The app is already relying on some HTML5 technologies so the solution does not have to be compatible with the older browsers ... But the "feedback loop" part is important as I've struggled with this before ...
Thanks :)
since your already using Backbone, I would stick with Backbone's Router objects. It will be easier to use what's already available in your app instead of trying to bring something new in the mix.
As for your feedback loop problem, I've solved this by never firing my router methods from code.
The gist of it is that I let my JavaScript objects control the state of the application, and do the work for me. When I do call router.navigate, I never pass true as the second argument. I only call router.navigate in response to a state change in my app, to update the hash fragment in my browser window. Here's the thing: This is purely a response to the state of the application having changed. I never use router.navigate to change the state of my app.
Hope that helps