Alert after fullscreen loading indicator - reactjs

I need to display a fullscreen loading indicator while a request is being processed, in case request fails I might need to show an Alert with an error message immediately after the loading indicator is dismissed. Using a Modal to show the loading indicator works great on Android but unless a delay is added between dismissing the loading indicator and displaying the Alert iOS is going to hang up, which is a known issue.
To solve this problem I've created a View-based ProgressHUD component to display loading indicator and put it as an App component child below all other components like this:
<View style={{ flex: 1 }}>
<AuthScreensStack />
<ProgressHUD isLoading={false} />
</View>
The indicator itself works as expected and nothing hangs up. The problem I'm facing now is deciding how to toggle this ProgressHUD. I'm using redux-saga middleware so I could probably move the ProgressHUD outside of App component into something like a LayoutComponent and connect it to the redux storage to observe some isLoading flag, but that will require me to add an additional action to each of my sagas, which will make them messy. Ideally I would like to have control over the ProgressHUD in each of the screens that need to use it but rendering it in them will render below navigation bar / above tab bar. Is there a way, perhaps, to render a View over the entire app's window from within a screen that's displayed via react-navigation's navigator? Any suggestions on how to handle this would be greatly appreciated.

Since you're already using redux-saga, therefore you can chain it in the generators.
Considering an action such as loadingOverlayVisible triggers the Modal with the loading indicator
Either you can customize it in your saga where your firing it as
export function * submit() {
try {
yield put(loadingOverlayVisible(true)) // Modal Open
const result = yield call(sampleApiCall)
yield put(loadingOverlayVisible(false)) // Modal Close
if(result && result.ok) {
yield call(Alert.alert, 'Success', 'Success Response') // Alert Called
//... Other stuff
}
} catch(ex) {
yield call(Alert.alert, 'Success', 'Success Response') // Alert Called
}
}
OR
Make a separate middleware for ajax request interceptor such as
export function * interceptor({url, params}) {
try {
yield put(loadingOverlayVisible(true)) // Modal Open
const result = yield call(sampleApiCall)
yield put(loadingOverlayVisible(false)) // Modal Close
} catch(ex) {
throw ex // Either handle it here or in your other generators
}
}

Related

React/Redux : Detect and exectute instructions before component destruction

Ola,
In my redux state, I have a isEditing boolean value, initiate at false, to manage a profile editing mode. I create a redux action to toggle this state. Below, some screen of the component render.
It works in most cases:
When I click on Edit name, I toggle to true and display the edit form
When I click on Save (or Cancel), it perform (or not) api request, then toggle to false, displaying the initial component
But if I start editing then quit page manualy (via logo link or url), and then come back to this page, obviously, the edit mode is still active at true.
I would like to put my state to false when I leave page, but I don't find any option to dispatch an action before component destroyed (like old componentWillUnmount() class programming method or beforeUnmount VueJS equivalent)
PS : I use react router V6. It seems a hook was implemented during beta but never released, and no news since :(
An alternative is to force value to false on component creation, with useEffect. It works, but I think it's not the right place. I see the edit mode opened then close in my ui during a few ms.
Thanks in advance
Try using the clean up on an useEffect hook
useEffect(() => {
// Specify how to clean up after this effect:
return function cleanup() {
// make redux call to toggle edit mode
};
});
I believe you could dispatch an action in the useEffect return value like useEffect(() => { return () => dispatch(changeEditMode(false)) }, []). It is mostly similar to a componentWillUnmount().

Display a loading text/spinner until a component is fully loaded(text,images...etc) in React

I searched for a solution like this but I just couldn't find it properly so I am asking this question if anyone can help.
This is a Sandbox that I made and the idea is something like this: I want to show a loading text until my component(let's say a whole website: including images, text.. etc..) is fully loaded, tried to make this with useEffect hook but the useEffect only shows the loading text until the component is mounted, and the hook does that, but there are things like images inside this component that aren't fully loaded yet, so this does not work the way I want. I would appreciate it if anyone knows a way to make this work, there is a lot of information on the web for making something like this with a setTimeout but I think this is a bit of a tricky/fake way to do it because the loading spinner should show depending on the speed of your ISP right? so for users with a better internet connection the loading text/spinner time will be shorter and for others, it will be longer.
Link to Sandbox
you can use the following function on your component :
document.onreadystatechange = function () {
if (document.readyState === 'complete') {
console.log("do something");
}
}
or controll all document's loading period using
switch (document.readyState) {
case "loading":
// The document is still loading.
break;
case "interactive":
// The document has finished loading. We can now access the DOM elements.
// But sub-resources such as scripts, images, stylesheets and frames are still loading.
console.log('do something')
break;
case "complete":
// The page is fully loaded.
console.log("do something");
break;
}
you can also use this function if you need it :
window.addEventListener("load", event => {
var image = document.querySelector('img');
var isLoaded = image.complete && image.naturalHeight !== 0;
console.log(isLoaded);
});
You could have a 'loading' state that is true at first and then change it's value with the onload function.
You could use it like this:
<div onload={setLoading(false)}>
<img src="..." />
<img src="..." />
<img src="..." />
</div>
Onload executes when all of it's children content has finished loading. You could read more about this at https://www.w3schools.com/tags/ev_onload.asp

Show warning on leaving without saving

I'm working on a React page which has a card component which opens on clicking a button. I'm trying to show a warning if the user tries to close the card without saving the changes. The card doesn't have a close button, it closes when clicking anywhere on the screen outside of the card.
I've built a similar warning modal by checking if the route has changed, however since in this case the card component is part of the same page I cannot apply the same logic.
<CardSidebar
onHide={(e) => this.setState({ showSidebar: false})}
>
<FormComponent
data={this.state.item}
filterTypes={this.state.filterTypes}
dataFields={stores.dataFieldStore.dataFieldsForDropDownComponents}
refresh={this.refreshListHandler}
cancelHandler={this.cancelHandler}
/>
<>
<RouteLeavingGuard
// when={?}
/>
</>
</CardSidebar>
So basically you want to know when the form is dirty and data is not saved so the guard would pop up. As far as I can see you are not using any library for handling this kind of behavior in forms so you need to build custom. I also don't see that you are using something as Redux so you need to lift state up and keep the isDirty value in the state of the component that is shown in the snippet.
//This code goes in the snippet that you pasted
state={
isDirty:false
}
isDirtyHandler(value){
this.setState({isDirty:value})
}
Pass the isDirtyHandler and isDirty as prop for check into the <FormComponent/> and inside the component make the following check
//This goes in <FormComponent/>
componentDidUpdate(prevProps, prevState) {
if(this.state.data !== prevState.data && !this.props.isDirty) {
this.props.isDirtyHandler(true)
}
onSubmitHandler(){
this.props.isDirtyHandler(false)
//whole logic for submitting the form
}
and just in the guard you are checking if form is dirty
<RouteLeavingGuard
popUp={isDirty}
/>

reactstrap alert automatic hidden

I am new in React and I use Alert - Dismissing from Reactstrap , I need the alert to automatically disappear after 2s. I tried to find some function that could be done, but unfortunately I did not. Thank you for help
Please have a look at this code,
hiding alert after a specific time
when you want to show the alert on some action, you can enable a state associated with that alert and disable it when you want to hide it.
I had a similar problem. My purpose was to show an Alert message after a Modal closed. I am using react-bootstrap for Modal and Alert component with useState and use Effects hooks.
const [visibleAlert, setVisibleAlert] = useState(false); --> init state
const handleVisible = () => { ---> Last State for Alert
setAlertVisible(true)
setTimeout(() => { ---> 2 seconds later which is closing
setAlertVisible(false)
}, 2000);
}
useEffect(() => {
handleClose(); ----> This is for Modal
return () => {
handleVisible(); ---> This is for Alert message
};
And this is my Alert component.
<Alert show={visibleAlert} variant="success"} dismissible>
Employee List Updated Successfully.
</Alert>
Alerts are something I like to play with: here is a full dynamic example where I set 1 alert and control it based on my requirements.
1st we need to set the alert. If you are using reactstrap use capital A for alerts
<Alert color={this.state.alertColor} isOpen={this.state.Alertvisible} toggle={(e) => this.setState({Alertvisible: false})}> {this.state.message} </Alert>
as you can see I can dynamically control the color, the visibility and the content of the alert without having to set multiple alerts.
here is the part where I control the alert
this.setState({
Alertvisible: true,
alertColor: 'success',
message: 'Alerts are awesome!'},
()=> {window.setTimeout(()=>{this.setState({Alertvisible:false})},8000)
});
So let me explain what is going on here!
with alertvisible: true we show the alert,
with alertcolor: we set the color according to the reactstrap or bootstrap
message: here we put the content of what we want to display
at the end you notice the window.setTimeout(()=> this is set to timeout in 8000 (8 seconds)
don't forget to add your states in the constructor.
I hope this helps :D

Cancel/Allow react-router transition after confirmation in via dialog box on ComponentWillUnmount

I'm building a Redux application. I want user to confirmation if they want to leave the Component without saving the data or cancel the transition and save it and maybe then leave.
For example, is there any way to stop a component from unmounting?
A better way is to create the following routerWillLeave hook if you are already using react-router.
componentDidMount() {
this.props.router.setRouteLeaveHook(this.props.route, this.beforeUnload);
}
routerWillLeave(e) {
// check for a condition here
if (this.state.allowLeave === false) {
const message = 'Are you sure?';
(e || window.event).returnValue = message;
return message;
}
}
Also, to make sure this.props.router is available, you must export your component as:
export default withRouter(MyComponent);
See docs at https://github.com/reactjs/react-router/blob/master/docs/guides/ConfirmingNavigation.md.
There is no way to prevent component from unmounting. You can use window.onbeforeunload to prevent user from closing current tab and save data in background on componentWillUnmount. That's how I do it in my app.
If window.onbeforeunload returns anything except undefined it will trigger a confirmation popup.
window.onbeforeunload = () => 'Are you sure?';

Resources