For a consistent user experience, I'd like my react app to reverse its state when the user clicks the browser back button.
For example, if I change an element in the state with a function call:
changeVar = (idx) => (event) => {
this.setState({thisIndex: idx});
//how to notify browser stack of this change?
}
How could I add this to the browser stack so that users can click the back button in the browser to reverse the state change?
So in general question is "how could I handle browser Back/Next button clicked?" or "How could I react on user navigates through history?"
Here such a thing like History API with its .pushState comes to the scene.
In short:
on each significant state change you call history.pushState(stateData)
once user clicks Back button it does not actually navigate away to different URL rather change current state only(but only if previous state in the stack has been created with .pushState or .replaceState)
your code detects if history navigation occurs(Back button been clicked) by listening to popstate event
based on appropriate state data that you read from history.state you restore application state appropriately
So far the last question is how to put all the data across your application in single object and to restore all the application with it modules' states later. And here redux comes to the help. Redux suppose you have just single Store over all your application. In other words all the state is already contained in single object that you just need to pass into .pushState() to store and to restore it after Back button is clicked.
PS remember I told about significant change? since "all the data all over the application" is large enough it would make overhead to store store it million times in the memory. Also it would be a silly if clicking Back button say just collapse a dropdown.
PPS and since history is global there is no way to store/restore state on per-component way. so maybe(just maybe) it's better to implement something like "state change history" for your component and propose user some different control to restore its state(instead of clicking Back button in browser)
Related
I'm working on an App which displays some information to the user. This information changes multiple times per day (sometimes multiple times per hour).
I'm using Firebase and setting listeners for this information.
Is it reliable to assume that these listeners will always work?
If the app is not closed (so the component is never unmounted), will the listeners ever expire/close?
Is implementing a pull-to-refresh a more reliable way to update information.
The situation I'm worried about is something happening with a listener and the only way the user can then update the app is by shutting it down and restarting to trigger new listeners.
once the app is closed the listner wont work
no it ll keep listnening if the system have enough battery or the app is not closed by the system. [when app remains in background the app is disbaled by android system to save battery and when the user comes it restarts]
it depends upon the kind of application is. if the app is some stocks or chat kind of thing then data must stream in real time while if the app displays some posts by some other user like in twitter user profile then pull to refresh is ok
RECOMMEND: you should also make a retrial function to check the state of the listener if it goes of then retry [helpful where there is a network break] moreover you should also give a mechanism to the user to refresh as it imprves the UX ;)
You have to understand the react component lifecycle before getting an answer to this, listener will always be a part of some component and listener will be initialized when some component is initialized into the memory and listener life is dependent on that component once that component is unmounted from the memory that specific listener will not be invoked so now the answer of your first question is.
Even the app is not closed and you are navigating between the different screens and you put your listener in some child component and that component is unmounted from the memory your listener will not work.
Now came to the second question which is almost answered in my first answer.
So as I said in the first answer Until that component unmounted from the memory, the listener will work unless you close the app or the operating system kills the app due to some reason but as long as the component keeps mounted into the memory your listener will keep working.
I believe adding a pull to refresh is more convenient in your case another option is that you can use a mixture of your change listener and focus listener of your navigation library, When the user focuses on some screen then you can fetch newer data and in that way always fresh data will be displayed instead of manual refresh.
Redux state holds flag for unsaved changes, and I want to prompt user when navigating (clicks a Link) if this flag is set. I'm using react-router-component. I didn't find how to do this in documentation.
Anyone reaching this post in 2018 and using the react router 4+, I'd suggest reading this reacttraining example
TL;DR use the Prompt component at the top
<Prompt
when={hasUnsavedChanges}
message="There are unsaved changes, do you wish to discard them?"
/>
You should simply be able to create your own Link component (that inherits from Router.NavigatableMixin, example here https://github.com/STRML/react-router-component/issues/105#issuecomment-63874805 and here http://strml.viewdocs.io/react-router-component/recipes/custom-link/).
Then you just handle click event on that component by prompting user if they want to navigate away if 'yes' you just continue with this.navigate(...) (from within your component, inheriting from Navigatable).
I'm working on a project using react with flux architecture.
I have several views and a store called ContextStore in which I save the current view in the state, so that when an action to change the view is triggered this store change his state and the Main view listen and change it.
But the problem is that always when I refresh the page with F5 it always goes to the initial Views.
What is more, if I press the back button the View has no change.
I think that my problem is because when I refresh the Main view loads again the initial state. How could I solve it?
Thanks!
You might want to look into using a router to manage your views. Here's the one I use: https://github.com/rackt/react-router. When you transition to different views (routes) it adds to the history stack so you can use the back button. However, I don't have the use case where you need to stay on the current view when you refresh, so you might need to use cookies or session storage in those instances in any case.
You are right, when hitting F5 you are completely reseting all javascript, ergo the store looses its state. You need to use some kind of storage for saving the state. Classical ways are cookies, or you could use IndexedDB which is included into HTML5
I'm trying to automate a page generated by React: record the user interaction in the page and then play it back for testing purposes.
In the simplest case, the playback sets the values of various inputs and triggers change events.
Unfortunately, after my code sets the values and simulates the click on the form submit button, React steps in and resets the values to those from its internal model.
Is there a way to force React to update from the values in the DOM?
If not, is there a way for me to hook into React and change the values, given the DOM node? Something like (totally bogus pseudocode): require("react").findComponentForDomNode('xxx').setValue('yyy') ?
Make sure that your form is using "uncontrolled" components, or at the very least that you're allowing user input in your controlled components.
http://facebook.github.io/react/docs/forms.html
Alternatively, you should be able to accomplish this with React's testing utilities:
http://facebook.github.io/react/docs/test-utils.html
This lets you perform actions such as:
React.addons.TestUtils.Simulate.change(node, {target: {value: 'Hello, world'}});
In a single page application, is there a way of switching back and forth to an AngularJS route and to display it back in the same state as it was shown before?
Usually this would be implemented by binding data in a parent scope. While this is easy to set up for lightweight view, it can be cumbersome when doing it for views holding lots of graphical elements.
Here is an example, where having the previous route state remembered could enhance user experience: on the following page, imagine that
you stand on Item 1 and select Tab 2
then move to Item 2
finally switch back to Item 1: Tab 2 is not selected anymore :-(
http://angular-route-segment.com/src/example/#/section1/1
It seems the views are destroyed/constructed when switching back and forth between routes.
A solution would be about storing the state of the user interface in a parent scope but it has the following pitfalls:
creating an object storing all the little details of the user interface
creating complex logic about -saving and- resetting the UI in the same state as before
storing UI state in a data model does not sound that MVC-ish
Using show/hide of div storing the views saves the state but then no route is used and the switching business must be implemented by hand. I like using routes because 1. of the browser history navigation (hash in the url) and 2. it is easy to set up.
Having the UI state not remembered is like having Chrome to reload pages when switching back and forth between tabs: not very user friendly.
Is there an Angular-way?
Your $routeSegment approach is very interesting. The $routeSegment service could plug into the $routeChangeStart event in order to
Somehow keep a "sub path history" on all paths seen so far, maybe only for those explicitly configured to keep their UI state. In your example for the path "/section1/1" the stored sub path would be "/Y" if tab 2 was selected. Things get interesting, as also dynamic paths with $routeParams might need to be covered.
Use this history for redirecting by using $location.path in the event handler. So a $routeChangeStart event with next.originalPath being "/section1/1" might be redirected to "/section/1/Y"