reactstrap alert automatic hidden - reactjs

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

Related

Conditional rendering with useEffect / useState, why is there a delay in the DOM when switching components?

Intro / Context
I am trying to build an application using React that allows for image or video display based on a chosen menu item. I am currently using Advanced Custom Fields within WordPress to build my data objects and using graphQL to query them into my project.
I want the application to display either a video component or an image component. This choice will be determined through conditional rendering and based on the contents of the object's fields.
Each object contains a title, an image field and a video field. If the entry in question should be displayed as an image the video field will be set as the string 'null'. All fields will return strings regardless.
I am using useState to target a particularly active field, however, despite triggering a change in state conditional rendering does not appear to change.
The Application
This is my approach
function Display({ objects }) {
const [setVisualOption, changeVisualOption] = useState(false);
const [appState, setState] = useState({
myObjects: objects,
activeTitle: "null",
activeImage: "null",
activeMediaUrl: "null",
});
function toggleActive(index, trackIndex) {
setState({
...appState,
activeTitle: appState.myObjects[index].title,
activeImage: appState.myObjects[index].image[0].mediaItemUrl,
activeMediaUrl: appState.myObjects[index].mediastreamurl,
});
changeVisualOption(appState.activeImage.includes("null"));
}
useEffect(() => {}, [
appState.activeTitle,
appState.activeImage,
appState.activeMediaUrl,
setVisualOption,
]);
return (
<div className="display">
<div className="list-box-right>
{appState.myObjects.map((element, index) => (
<>
<div
key={index}
className="menu-item"
onClick={() => {
toggleActive(index);
}}
>
{element.title}
</div>
</>
))}
</div>
<div className="right-grid">
{setVisualOption ? (
<VideoComponent activeImage={appState.activeImage}></VideoComponent>
) : (
<ImageComponent activeImage={appState.activeImage}></SingleImage>
)}
</div>
</div>
);
}
The summarise, to component takes objects as prop which are being passed down from another component making the graphQL query. I am then setting the initial values of useState as an object and setting an activeTitle, activeImage and activeMediaUrl as null.
I am then using a function to toggle the active items using the setState modifier based upon the index that is clicked within the return statement. From there I am using setVisualOption and evaluating whether the activeImage is contains 'null' (null.jpg), if this is true setVisualOption will be set to true allowing the Video Component to be rendered
The Problem
To be clear, there are no errors being produced and the problem is a slight rendering issue where it requires double clicks to alter the state and trigger the correct response from the tertiary operator.
The issue is within the conditional rendering. If I set my object fields to all images and return only the Image Component there are no issues, and the state change can be seen to register visually as you click down the listed options.
It is only when I introduce the conditional rendering that there is a delay, the first click does not generate the correct response from the component I am trying to display however the second click triggers the right response.
As you can see, I am also using useEffect to try and trigger a rendered response when any of the described states change but still encounter the same problem.
Does anyone know what is the cause of this bug? when looking at the console.log of setVisualOption is not appearing as true on first click when it aught to.
Any insights would be great thanks
You set your visual option right after you set your appState, this is why appState.activeImage in changeVisualOption is not updated because state updates in React is asynchronous. You can either use useEffect to update visual option when the appState changes or you can use appState.myObjects[index].image[0].mediaItemUrl in changeVisualOption
function toggleActive(index, trackIndex) {
setState({
...appState,
activeTitle: appState.myObjects[index].title,
activeImage: appState.myObjects[index].image[0].mediaItemUrl,
activeMediaUrl: appState.myObjects[index].mediastreamurl,
})
changeVisualOption(appState.myObjects[index].image[0].mediaItemUrl.includes("null"))
}
or
useEffect(() => {
changeVisualOption(appState.activeImage.includes("null"))
}, [appState])

Prevent navigation until React form is validated

I'm trying to implement a validation functionality in React wherein the user will fill in a form, and then the user can navigate to other tabs of the application.
What i want to do is disabling the navigation until certain parts of the form has been filled, if the user attempts to change the tabs without filling said fields, a message will appear directly on the page to alert the user that the fields are required.
My current approach is to capture the event prior to the page switch, check for the form's validity, and then decide whether or not the user can navigate based on said.
The problem is I have no idea which event to capture or how to prevent user's navigation, can someone help me?
EDIT:
Here's what i've tried so far:
componentWillUnmount() {
this.handleValidation();
}
handleValidation = () => {
if (this.invalidForm()) {
this.setState({ showValidation: true });
this.preventNavigation();
}
};
preventNavigation = () => {
window.location.reload();
}
render()
return (
///Form information...
{this.state.showValidation && (
<div>
You must provide all required information
</div>
)}
)
I've thought that by using location.reload in componentWillUnmount(), the page would be reloaded before the navigation (hence, making the user stay in the old page), but what really happens is that it navigates to the other tab, then proceeds to reload there.

Detect mouse click and change state in React

I have a div which is displayed depending upon a variable- eg: showDiv. After i set showDiv= true, div will appear.
{showDiv && <div id="someid"> text</div>}
Have set a timeout to change variable value so that div will disappear after a time (7 seconds)
thisState.setState({showDiv:true});
setTimeout(function(){
thisState.setState({false});
}.bind(this),7000);
How can i add a code to detect any mouse click and change variable based on that ? Requirement is that, div should disappear either
1. after 7 seconds (already done)
2. based on a click event (if user just clicks on the screen)
Any thoughts ?
You are looking for a window event-listener essentially.
componentDidMount(){
window.addEventListener("click", this.hideDiv)
}
hideDiv = () => {
if(this.state.showDiv){
this.setState({
showDiv: false
})
}
}
Also remember to remove that listener before the component unmounts:
componentWillUnmount{
window.removeEventListener("click", this.hideDiv)
}
See working sandbox: https://codesandbox.io/s/stupefied-silence-snhnw

Alert after fullscreen loading indicator

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
}
}

How to wait and fade an element out?

I have an alert box to confirm that the user has successfully subscribed:
<div className="alert alert-success">
<strong>Success!</strong> Thank you for subscribing!
</div>
When a user sends an email, I'm changing the "subscribed" state to true.
What I want is to:
Show the alert box when the subscribed state is true
Wait for 2 seconds
Make it fade out
How can I do this?
May 2021 update: as tolga and Alexey Nikonov correctly noted in their answers, it’s possible to give away control over how long the alert is being shown (in the original question, 2 seconds) to the transition-delay property and a smart component state management based on the transitionend DOM event. Also, hooks are these days recommended to handle component’s internal state, not setState. So I updated my answer a bit:
function App(props) {
const [isShowingAlert, setShowingAlert] = React.useState(false);
return (
<div>
<div
className={`alert alert-success ${isShowingAlert ? 'alert-shown' : 'alert-hidden'}`}
onTransitionEnd={() => setShowingAlert(false)}
>
<strong>Success!</strong> Thank you for subscribing!
</div>
<button onClick={() => setShowingAlert(true)}>
Show alert
</button>
(and other children)
</div>
);
}
The delay is then specified in the alert-hidden class in CSS:
.alert-hidden {
opacity: 0;
transition: all 250ms linear 2s; // <- the last value defines transition-delay
}
The actual change of isShowingAlert is, in fact, near-instant: from false to true, then immediately from true to false. But because the transition to opacity: 0 is delayed by 2 seconds, the user sees the message for this duration.
Feel free to play around with Codepen with this example.
Since React renders data into DOM, you need to keep a variable that first has one value, and then another, so that the message is first shown and then hidden. You could remove the DOM element directly with jQuery's fadeOut, but manipulating DOM can cause problems.
So, the idea is, you have a certain property that can have one of two values. The closest implementation is a boolean. Since a message box is always in DOM, it's a child of some element. In React, an element is result of rendering a component, and so when you render a component, it can have as many children as you want. So you could add a message box to it.
Next, this component has to have a certain property that you can easily change and be completely sure that, as soon as you change it, the component gets re-rendered with new data. It's component state!
class App extends React.Component {
constructor() {
super();
this.state = {
showingAlert: false
};
}
handleClickShowAlert() {
this.setState({
showingAlert: true
});
setTimeout(() => {
this.setState({
showingAlert: false
});
}, 2000);
}
render() {
return (
<div>
<div className={`alert alert-success ${this.state.showingAlert ? 'alert-shown' : 'alert-hidden'}`}>
<strong>Success!</strong> Thank you for subscribing!
</div>
<button onClick={this.handleClickShowAlert.bind(this)}>
Show alert
</button>
(and other children)
</div>
);
}
}
Here, you can see that, for message box, either alert-shown or alert-hidden classname is set, depending on the value (truthiness) of showingAlert property of component state. You can then use transition CSS property to make hiding/showing appearance smooth.
So, instead of waiting for the user to click button to show the message box, you need to update component state on a certain event, obviously.
That should be good to start with. Next, try to play around with CSS transitions, display and height CSS properties of the message box, to see how it behaves and if the smooth transition happening in these cases.
Good luck!
PS. See a Codepen for that.
The correct way is to use Transition handler for Fade-in/out
In ReactJS there is synthetic event to wait till fade-out is finished: onTransitionEnd.
NOTE there are different css effects associated with different handlers. Fade is a Transition not an Animation effect.
Here is my example:
const Backdrop = () => {
const {isDropped, hideIt} = useContext(BackdropContext);
const [isShown, setState] = useState(true);
const removeItFromDOM = () => {
debugger
setState(false)
};
return isShown
? <div className={`modal-backdrop ${isDropped ? 'show' : ''} fade` } onClick={hideIt} onTransitionEnd={removeItFromDOM}/>
: null
}
An other way is to solve this with a CSS3 transition.
https://www.tutorialspoint.com/css/css_animation_fade_out.htm
You can add a new class to the alert (like .hidden) and then you can relate .hidden with the class you defined for the alert.
alert.hidden{
// Here you can define a css transition
}
In this solution you don't have to add a setInterval or anything, since css3 transitions already process it on browser render.

Resources