how to hide a component in react js after a few second - reactjs

hi I design this alert component :
import React from 'react';
import { Alert } from 'antd';
export default function CustomAlert (props) {
return (
<React.Fragment>
{
props.visible ?
<Alert message={props.message} style={{textAlign: 'right', direction: 'rtl' , position: 'fixed', width:'100%', zIndex:'100'}} closable afterClose={props.handleClose}/>
:
null
}
</React.Fragment>
)
}
but I want to hide the alert after 5 second. how can I do this?

You can use setTimeout to auto close the Alert something like this. Find the working example here
export default function CustomAlert(props) {
const [visible, setVisible] = React.useState(props.visible);
React.useEffect(() => {
visible &&
setTimeout(() => {
setVisible(false);
}, props.closeAfter);
}, [props.closeAfter, visible, setVisible]);
return (
<React.Fragment>
{visible ? (
<Alert
message={props.message}
style={{
textAlign: "right",
direction: "rtl",
position: "fixed",
width: "100%",
zIndex: "100"
}}
closable
afterClose={props.handleClose}
/>
) : null}
</React.Fragment>
);
}
And use the component like this in other files,
<CustomAlert visible message="Test Message" closeAfter={5000} />

I solve my problem with this style:
.alert{
-moz-animation: cssAnimation 0s ease-in 15s forwards;
/* Firefox */
-webkit-animation: cssAnimation 0s ease-in 15s forwards;
/* Safari and Chrome */
-o-animation: cssAnimation 0s ease-in 15s forwards;
/* Opera */
animation: cssAnimation 0s ease-in 15s forwards;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
text-align: right ;
direction: rtl ;
position: fixed;
width: 100% ;
z-index: 100;
}
#keyframes cssAnimation {
to {
width:0;
height:0;
overflow:hidden;
z-index: -100;
}
}
#-webkit-keyframes cssAnimation {
to {
width:0;
height:0;
visibility:hidden;
z-index: -100;
}
}

I posted an answer with css styling but here is a better answer:
import React, {useEffect} from 'react';
import { Alert } from 'antd';
export default function CustomAlert(props) {
useEffect(() => {
setInterval(() => {
props.handleClose();
},5000 )
}, [])
return (
<React.Fragment>
{props.visible ? (
<Alert
message={props.message}
style={{
textAlign: "right",
direction: "rtl",
position: "fixed",
width: "100%",
zIndex: "100"
}}
closable
afterClose={props.handleClose}
/>
) : null}
</React.Fragment>
);
}

Related

React Transition Group Dynamically Change Slide Direction

I'm creating a mobile navigation menu and using CSSTransition component from React Transition Group to handle animating in the different levels of my navigation.
I am able to successfully animate in different levels but only in one direction. For instance, the content will enter in from the right and exit to the left. The part that is confusing to me is when i need to change the direction that the content animates in or out.
For my example lets say I have 3 slides
Initially slide #2 would enter in from the right If we go to slide #3 it would exit left.
If we are on slide #3 and want to go back to slide #2 then I want slide #2 to enter in from the right.
import { useState } from 'react';
import { CSSTransition } from 'react-transition-group';
import './App.css';
const App = () => {
const [page, setPage] = useState(1);
return (
<>
Page: {page}
<nav>
<button onClick={() => page !== 1 && setPage(page - 1)}>Prev</button>
<button onClick={() => page >= 1 && page <= 2 && setPage(page + 1)}>
Next
</button>
</nav>
<div className='content'>
<CSSTransition
in={page === 1}
classNames='slide'
timeout={500}
unmountOnExit
>
<SlideOne />
</CSSTransition>
<CSSTransition
in={page === 2}
classNames='slide'
timeout={500}
unmountOnExit
>
<SlideTwo />
</CSSTransition>
<CSSTransition
in={page === 3}
classNames='slide'
timeout={500}
unmountOnExit
>
<SlideThree />
</CSSTransition>
</div>
</>
);
};
const SlideOne = () => {
return <h3>Hello From Slide One</h3>;
};
const SlideTwo = () => {
return <h3>Hello From Slide Two</h3>;
};
const SlideThree = () => {
return <h3>Hello From Slide Three</h3>;
};
export default App;
.content {
width: 200px;
height: 100px;
overflow: hidden;
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.1);
padding: 1rem;
position: relative;
}
h3 {
position: absolute;
}
.slide-enter {
opacity: 0;
transform: translateX(100%);
}
.slide-enter-active {
opacity: 1;
transform: translateX(0%);
transition: all 0.5s;
}
.slide-exit {
opacity: 1;
transform: translateX(0%);
}
.slide-exit-active {
opacity: 0;
transform: translateX(-100%);
transition: all 0.5s;
}
import { useState } from "react";
import { CSSTransition, TransitionGroup } from "react-transition-group";
import "./App.css";
const App = () => {
const [page, setPage] = useState(1);
const [direction, setDirection] = useState("left");
return (
<>
Page: {page}
<nav>
<button
onClick={() => {
page !== 1 && setPage(page - 1);
direction !== "right" && setDirection("right");
}}
>
{" "}
Prev
</button>
<button
onClick={() => {
page >= 1 && page <= 2 && setPage(page + 1);
direction !== "left" && setDirection("left");
}}
>
Next
</button>
</nav>
<div className="content">
{/* <TransitionGroup> */}
<CSSTransition
in={page === 1}
classNames={`slide-${direction}`}
timeout={500}
unmountOnExit
>
<SlideOne />
</CSSTransition>
<CSSTransition
in={page === 2}
classNames={`slide-${direction}`}
timeout={500}
unmountOnExit
>
<SlideTwo />
</CSSTransition>
<CSSTransition
in={page === 3}
classNames={`slide-${direction}`}
timeout={500}
unmountOnExit
>
<SlideThree />
</CSSTransition>
{/* </TransitionGroup> */}
</div>
</>
);
};
const SlideOne = () => {
return <h3>Hello From Slide One</h3>;
};
const SlideTwo = () => {
return <h3>Hello From Slide Two</h3>;
};
const SlideThree = () => {
return <h3>Hello From Slide Three</h3>;
};
export default App;
.content {
width: 200px;
height: 100px;
overflow: hidden;
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.1);
padding: 1rem;
position: relative;
}
h3 {
position: absolute;
}
.slide-left-enter {
opacity: 0;
transform: translateX(100%);
}
.slide-left-enter-active {
opacity: 1;
transform: translateX(0%);
transition: all 2000ms;
}
.slide-left-exit {
opacity: 1;
transform: translateX(0%);
}
.slide-left-exit-active {
opacity: 0;
transform: translateX(-100%);
transition: all 2000ms;
}
.slide-right-enter {
opacity: 0;
transform: translateX(-100%);
}
.slide-right-enter-active {
opacity: 1;
transform: translateX(0%);
transition: all 2000ms;
}
.slide-right-exit {
opacity: 1;
transform: translateX(0%);
}
.slide-right-exit-active {
opacity: 0;
transform: translateX(100%);
transition: all 2000ms;
}
the trick is to reverse the translation on every key button

StopPropagation react google maps autocomplete

I would like to stopPropagation of https://react-google-maps-api-docs.netlify.app/#autocomplete.
The autocomplete works well but I need to use it in a popover and when I select a place the popover automatically closes.
If there is another library that works well with popovers and modals
const [autocomplete, setAutocomplete] = useState<any>(null);
const onLoad = (auto: any) => {
if (!autocomplete) {
setAutocomplete(auto);
}
};
const onPlaceChanged = () => {
if (autocomplete) {
console.log(autocomplete?.getPlace());
} else {
console.log('Autocomplete is not loaded yet!');
}
};
<Autocomplete
onLoad={onLoad}
onPlaceChanged={onPlaceChanged}
>
<chakra.input
type='text'
as={Input}
placeholder='Customized your placeholder'
style={{
boxSizing: `border-box`,
border: `1px solid transparent`,
width: `240px`,
height: `32px`,
padding: `0 12px`,
borderRadius: `3px`,
boxShadow: `0 2px 6px rgba(0, 0, 0, 0.3)`,
fontSize: `14px`,
outline: `none`,
textOverflow: `ellipses`,
position: 'absolute',
left: '50%',
marginLeft: '-120px',
animationName: 'none',
zIndex: 9999,
}}
/>
</Autocomplete>
I'm using chakraUI, I get help from discord(dodas user) here is the solution he make. Basically he catch the mousedown event(google block click event) and when the popover is open, select item or click trigger button just do nothing for others events just close popovers.
https://codesandbox.io/s/popovergoogle-autocomplete-6nvtb?file=/src/App.js:0-3329
import React, { useState, useEffect, useRef } from "react";
import {
Button,
Stack,
Popover,
PopoverTrigger,
PopoverContent,
PopoverHeader,
PopoverBody,
PopoverArrow,
PopoverCloseButton,
Box,
Portal,
PopoverFooter,
useRadioGroup,
useRadio
} from "#chakra-ui/core";
import { useEvent } from "react-use";
import {
GoogleMap,
useJsApiLoader,
Autocomplete
} from "#react-google-maps/api";
let autoComplete;
export function App() {
const { isLoaded, loadError } = useJsApiLoader({
googleMapsApiKey: "YOUR_KEY", // ,
libraries: ["places"]
// ...otherOptions
});
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
const openPopover = () => setIsPopoverOpen(true);
const closePopover = () => setIsPopoverOpen(false);
const triggerRef = useRef(null);
const popoverContentRef = useRef(null);
const [autocomplete, setAutocomplete] = useState(null);
const onLoad = (autocompleteInstance) => {
console.log("autocomplete: ", autocomplete);
setAutocomplete(autocompleteInstance);
};
const onPlaceChanged = () => {
if (autocomplete) {
console.log(autocomplete.getPlace());
} else {
console.log("Autocomplete is not loaded yet!");
}
};
useEvent("mousedown", (ev) => {
if (!isPopoverOpen) {
return;
}
const clickedInsideTrigger = triggerRef.current.contains(ev.target);
const clickedInsidePopover = popoverContentRef.current.contains(ev.target);
const clickedInsideAutocomplete =
ev.target.closest(".pac-container") != null;
if (
clickedInsideTrigger ||
clickedInsidePopover ||
clickedInsideAutocomplete
) {
return;
}
closePopover();
});
return (
<>
<Box width="100vw" height="100vh">
<Popover
isOpen={isPopoverOpen}
onOpen={openPopover}
onClose={closePopover}
closeOnBlur={false}
isLazy
placement="bottom-end"
>
<PopoverTrigger>
<Button ref={triggerRef}>Trigger</Button>
</PopoverTrigger>
<PopoverContent ref={popoverContentRef}>
<PopoverArrow />
<PopoverCloseButton />
<PopoverHeader>Confirmation!</PopoverHeader>
<PopoverBody minH="20rem">
{isLoaded && (
<Autocomplete onLoad={onLoad} onPlaceChanged={onPlaceChanged}>
<input
type="text"
placeholder="Customized your placeholder"
style={{
boxSizing: `border-box`,
border: `1px solid transparent`,
width: `240px`,
height: `32px`,
padding: `0 12px`,
borderRadius: `3px`,
boxShadow: `0 2px 6px rgba(0, 0, 0, 0.3)`,
fontSize: `14px`,
outline: `none`,
textOverflow: `ellipses`,
position: "absolute",
left: "50%",
marginLeft: "-120px"
}}
/>
</Autocomplete>
)}
</PopoverBody>
</PopoverContent>
</Popover>
</Box>
</>
);
}

CSSTransition from react-transition-group not applying classes

I'm trying to integrate CSSTransition to my Gatsby site, but it is not applying any of the classes. I'm utilizing CSS modules, and I've got a <div> that serves as the parent that fades in and out, essentially applying the fade effect to this and covering the content while it changes. It's got the class fadEffect. Here is my app-layout component, and the SASS.
AppLayout.tsx
import React, { ReactNode, useState } from 'react';
import { ApiContext } from 'contexts/ApiContext';
import { graphql, StaticQuery } from 'gatsby';
import { TransitionGroup, CSSTransition } from 'react-transition-group';
import { Devtools } from '../devtools/Devtools';
import { Footer } from '../footer/Footer';
import { Header } from '../header/Header';
import s from './AppLayout.scss';
interface AppLayoutProps {
children: ReactNode;
location: string;
}
const isDev = process.env.NODE_ENV === 'development';
// tslint:disable no-default-export
export default ({ children, location }: AppLayoutProps) => {
const [fadeEffectVisible, setFadeEffectVisible] = useState(false);
const handleFadeEffectEntered = () => {
setTimeout(() => {
setFadeEffectVisible(false);
}, 50);
};
return (
<StaticQuery
query={`${NavQuery}`}
render={(data) => (
<>
<ApiContext>
<Header navigationContent={data.prismic.allNavigations.edges[0].node} />
<CSSTransition
in={fadeEffectVisible}
timeout={150}
classNames={{
enter: s.fadeEffectEnter,
enterActive: s.fadeEffectEnterActive,
enterDone: s.fadeEffectEnterDone,
exit: s.fadeEffectExit,
exitActive: s.fadeEffectExitActive,
}}
onEntered={handleFadeEffectEntered}
>
<div className={s.fadeEffect} aria-hidden="true" />
</CSSTransition>
<TransitionGroup component={null}>
<CSSTransition
key={location}
timeout={150}
classNames={{
enter: s.pageEnter,
}}
>
<div className={s.layout}>
{children}
<Footer navigationItems={data.prismic.allNavigations.edges[0].node} />
{isDev && <Devtools />}
</div>
</CSSTransition>
</TransitionGroup>
</ApiContext>
</>
)}
/>
);
};
const NavQuery = graphql`
query NavQuery {
prismic {
allNavigations {
edges {
node {
...NotificationBar
...NavigationItems
...FooterNavigationItems
}
}
}
}
}
`;
AppLayout.scss
#import '~styles/config';
:global {
#import '~styles/base';
}
.layout {
display: block;
min-height: 100vh;
}
.pageEnter {
display: none;
}
.fadeEffect {
display: none;
position: fixed;
z-index: 9;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #fff;
transition: opacity 0.15s linear;
&Enter {
display: block;
opacity: 0;
}
&Active,
&Done,
&Exit {
display: block;
opacity: 1;
}
&ExitActive {
opacity: 0;
}
}
I'm happy to provide more details/code if this isn't enough. I'm newish to React and Gatsby, so I'm still learning the lingo. Thanks in advance.
I don't see part of your code where you are updating fadeEffectVisible to true for first CSSTransition and I don't see in property at all on second CSSTransition and I would bet that is your issue. Please take a look at this example from React Transition Group for understanding usage of properties.
App.js
function App() {
const [inProp, setInProp] = useState(false);
return (
<div>
<CSSTransition in={inProp} timeout={200} classNames="my-node">
<div>
{"I'll receive my-node-* classes"}
</div>
</CSSTransition>
<button type="button" onClick={() => setInProp(true)}>
Click to Enter
</button>
</div>
);
}
Style.css
.my-node-enter {
opacity: 0;
}
.my-node-enter-active {
opacity: 1;
transition: opacity 200ms;
}
.my-node-exit {
opacity: 1;
}
.my-node-exit-active {
opacity: 0;
transition: opacity 200ms;
}
When the in prop is set to true, the child component will first receive the class example-enter, then the example-enter-active will be added in the next tick.

React-select, open sub-menu when hover over an option

I'm trying to build a submenu inside a main menu with React-select, it should be something like this:
When hovering over an option from the main menu, it triggers the submenu to open at the side.
Is there a way to do this using react-select? I couldn't find any example or documentation on this, is there a function like ```optionOnMouseover`` for this? Thank you in advance!
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' },
];
...
<Select
value={...}
onChange={...}
options={options}
/>```
This is on click, but if you need on hover,
just modify it
import React, { useState } from "react";
import ReactDOM from "react-dom";
import Select, { components } from "react-select"
const CustomOption = (props) => {
const [submenu, setSubmenu] = useState(false)
const [height, setHeight] = useState(0)
const handleOption = (e) => {
if(submenu) {
setSubmenu(false)
} else {
setHeight(e.clientY)
setSubmenu(true)
}
}
const handleSubOption = (e) => {
console.log('clicked')
}
const { data } = props;
return data.custom ? (
<>
<div onClick={handleOption} className="customs">
{data.label} <span className="caret"/>
{
submenu && (
<div className="dropdown-submenu">
<div className="drops" onClick={handleSubOption}>
Test dropdown 1
</div>
<div className="drops" onClick={handleSubOption}>
Test dropdown 2
</div>
<div className="drops" onClick={handleSubOption}>
Test dropdown 3
</div>
</div>
)
}
</div>
<style jsx>{`
.customs {
height: 36px;
padding: 8px;
position: relative;
}
.drops {
height: 36px;
padding: 8px;
}
.customs:hover, .drops:hover {
background-color: #17cf76;
}
.dropdown-submenu {
position: fixed;
top: ${height - 10}px;
left: 410px;
min-height: 36px;
overflow: auto;
border: 1px solid hsl(0,0%,80%);
border-radius: 4px;
color: #212529;
}
`}</style>
</>
) : (
<components.Option {...props} />
);
};
const options = [
{ custom: true, label: "I'm a custom link", value: "cust" }
];
function App() {
return (
<>
<Select classNamePrefix="category-select" className="w-30" components={{ Option: CustomOption }} options={options} />
<style jsx global>{`
* {
font-family: sans-serif;
text-align: center;
}
.w-30 {
width: 30% !important;
}
`}</style>
</>
)
}
export default App

How to delay a component render in React?

I have an instagram widget thas uses iframe, but when I switch between routes, the widget loads too slow and does'nt have time to render properly.
Can You tell me, how to set delay rendering of the component, jr another solution to this problem?
Here is the component:
import React, { Component } from 'react';
const divStyle = [
{
border: 'none',
overflow: 'hidden',
width: '100%'
},
{
font: "10px/14px 'Roboto','Helvetica Neue',Arial,Helvetica,sans-serif",
fontWeight: '400',
width: '100%',
textAlign: 'right'
},
{
color: '#777',
textDecoration: 'none'
}
];
class Instagram extends Component {
render() {
return (
<div id="instagram">
<iframe src="https://snapwidget.com/embed/711808" className="snapwidget-widget" allowtransparency="true" frameborder="0" scrolling="no" style={divStyle[0]}></iframe>
</div>
);
}
}
export default Instagram;
Also the code is located in the CodeSandbox.
Thanks for any help!
This can be possible solution from your code sandbox.
NOTE: Please Replace your loader with loading div.
CodeSandbox: https://codesandbox.io/s/damp-platform-950yw
import React, { Component } from "react";
const divStyle = [
{
border: "none",
overflow: "hidden",
width: "100%"
},
{
font: "10px/14px 'Roboto','Helvetica Neue',Arial,Helvetica,sans-serif",
fontWeight: "400",
width: "100%",
textAlign: "right"
},
{
color: "#777",
textDecoration: "none"
}
];
class Instagram extends Component {
state = {
loading: true
}
handelOnLoad = () => {
this.setState({
loading: false
})
}
render() {
return (
<>
{this.state.loading && <div style={{
position: "fixed",
background: "rgba(0,0,0,0.7)",
top: 0,
bottom: 0,
right: 0,
left: 0,
color: "#fff"
}}>Loading</div>}
<div id="instagram">
<iframe
src="https://snapwidget.com/embed/711808"
className="snapwidget-widget"
allowtransparency="true"
frameborder="0"
scrolling="no"
style={divStyle[0]}
onLoad={this.handelOnLoad}
/>
</div>
</>
);
}
}
export default Instagram;
You can make use of state to render,
class Instagram extends Component {
state={
show: false
}
componentDidMount(){
setTimeout(()=>{
this.setState({show: true})
},5000) //runs after 5sec
}
render() {
return (
<div id="instagram">
{ this.state.show && <iframe src="https://snapwidget.com/embed/711808" className="snapwidget-widget" allowtransparency="true" frameborder="0" scrolling="no" style={divStyle[0]}></iframe> }
</div>
);
}
}

Resources