I am doing a project and I want to show a modal window to compulsorily accept some Cookies.
I need that cookie window to be launched automatically, without pressing any button, when the application starts, that is, before the dashboard is loaded.
This is my code:
ModalCookie.js
imports ...
const style = {
position: 'absolute',
top: '50%',
left: '50%',
};
export default function CookiesModal() {
const handleOpen = () => setOpen(true);
const [open, setOpen] = React.useState(false);
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setCookiesPreview(false);
setOpen(false);
};
const handleNotClose = (event, reason) => {
if (reason && reason == "backdropClick")
return;
}
const [value, setValue] = React.useState('1');
const handleChange = (event, newValue) => {
setValue(newValue);
};
return (
<ThemeProvider theme={theme}>
<div>
<Fade in={open}>
<Box>
<BootstrapDialog
onClose={handleNotClose}
aria-labelledby="customized-dialog-title"
open={open}
closeAfterTransition
BackdropComponent={Backdrop}
BackdropProps={{
timeout: 500,
}}
>
<BootstrapDialogTitle id="customized-dialog-title" onClose={handleClose}>
</BootstrapDialogTitle>
<TabContext value={value}>
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
<TabList onChange={handleChange} aria-label="lab API tabs example">
<Tab
label="AAAAA"
value="1" />
</TabList>
</Box>
<TabPanel value="1">
<p>...</p>
</TabPanel>
</TabContext>
<Button
onClick={handleClose}
variant="contained"
color="secondary"
>
Aceptar
</Button>
</BootstrapDialog>
</Box>
</Fade>
</div>
</ThemeProvider>
);
}
Config.js
// COOKIES
export const setCookiesPreview = ( state ) => {
localStorage.setItem('cookiesPreview', state)
}
// --
export const isCookiesPreview = () => {
const active=localStorage.getItem('cookiesPreview') ? localStorage.getItem('cookiesPreview') : true;
setCookiesPreview(false);
return(
active
);
}
And my dashboard:
imports...
// MAIN
export const Dashboard = () => {
const state = useSelector( state => state);
console.log('isCookiesPreview='+isCookiesPreview());
if(isCookiesPreview()){
console.log('CookiesPreview ON ------------------------------------------------')
setTimeout(() => {
CookiesModal.handleOpen();
}, 15000);
}
return (
<>
<ThemeProvider theme={theme}>
<div>
<HeaderBar/>
{(alertMessage != null) && (alertMessage.length>0) ? <Alert severity={alertSeverity}>{alertMessage}</Alert> : <></>}
<Grid container item={true} xs={12}>
<BodyGrid/>
</Grid>
<Grid container item={true} xs={12} pt={4}>
<BottomBar/>
</Grid>
</div>
</ThemeProvider>
</>
)
I am trying to use the handleOpen() constant from ModalCookie.js to open the window from Dashboard.js and save the locale that those cookies have been accepted so as not to show it the following times
I can't get the window to show up, but it does show me the logs I've put on the Dashboard related to cookies.
It tells me that HandleOpen is not a function.
Related
I have a code with which the user can select a file from their device. The Card component will display its name and operations that can be done with the file.
But my problem is that I don't know how to close this component if the user wants to cancel the action.
export default function DisplaySelectedFile() {
const [fileName, setFileName] = useState("");
console.log(setFileName)
return (
<div>
<SelectFileButton setFileName={setFileName} />
{fileName && <Card sx={styles.CommonStyle}>
<Stack spacing={10} direction="row" style={{paddingTop: "20px", paddingLeft: "10px"}}>
<div>{fileName}</div>
<Stack spacing={3} direction="row">
<div>Convert to</div>
<ConvertToFormatFile></ConvertToFormatFile>
</Stack>
<Button>CONVERT</Button>
<CloseIcon/>
</Stack>
</Card>}
</div>
);
}
I have added a button which should close the entire Card component. If I add the following code
<CloseIcon onClick={() => setFileName(false)}/>
If I add the following code, then the component closes. But the next time you select a file, this component does not open (only after reloading the page).
Tell me how to close the Card component correctly so that you can open it without problems
I would suggest to handle separately the card visibility and the file name value.
Something like this should work:
import React, { useState, useCallback } from "react";
const DisplaySelectedFile = () => {
const [fileName, setFileName] = useState(null);
const [showCard, setShowCard] = useState(false);
const handleSelectFile = useCallback(
(file) => {
setFileName(file);
file && setShowCard(true);
},
[setFileName, setShowCard]
);
const handleCloseCard = useCallback(() => {
setShowCard(false);
setFileName(null); // add this line only if it fits your use case
}, [setFileName, setShowCard]);
return (
<div>
<SelectFileButton setFileName={handleSelectFile} />
{showCard && (
<Card sx={styles.CommonStyle}>
<Stack
spacing={10}
direction="row"
style={{ paddingTop: "20px", paddingLeft: "10px" }}
>
<div>{fileName}</div>
<Stack spacing={3} direction="row">
<div>Convert to</div>
<ConvertToFormatFile></ConvertToFormatFile>
</Stack>
<Button>CONVERT</Button>
<CloseIcon onClick={handleCloseCard} />
</Stack>
</Card>
) || null}
</div>
);
}
export default DisplaySelectedFile;
I am working on a Frontend Mentor project and I am trying to pass the hover status from the parent component (App) to the child component (Listing).
You can see that I have created a state object called hover inside the App component and passed it to the Listing component but when the hover object updates the css style is not applied as it should be on the Typography element inside the Listing component. Or at least there isn't a re-render if it does.
App.js
let [hover, updateHover] = useState(false);
updateHover = () => {
if(hover === false){hover = true; console.log(hover); return(0);}
else{hover = false; console.log(hover); return;}
}
return (
<ThemeProvider theme={ theme }>
<div style={{backgroundColor:'hsl(180, 52%, 96%)',}}>
<div style={{backgroundImage:`url(${headerImage})`, backgroundSize:'cover', height:'10rem'}}></div>
<Box display="flex" justifyContent="center" alignItems="center">
<Box style={{width:'70%', marginTop:'5rem'}}>
<Card style={styles.listing} onMouseEnter={updateHover} onMouseLeave={updateHover}>
<CardActionArea href="#" className="listingHover">
<Listing id="one" hover={hover} />
</CardActionArea>
</Card>
</Box>
</Box>
</div>
</ThemeProvider>
);
}
export default App;
Listing.js
function Listing(props) {
let id = props.id
let hover = props.hover
return (
<React.Fragment>
<Box className="listing" display="flex" sx={{backgroundColor:'#fff', width:'100%', height:'7.3rem'}}>
<Box>
<Typography variant="h4"><Link className={hover ? 'jobTitle': null} href="#" color="secondary" underline="none">{jobs[id].name}</Link></Typography>
</Box>
</Box>
</Box>
</React.Fragment>
)
}
export default Listing
I think your problem here is that you re declared updateHover.
You should change the name and have something like
const [hover, setHover] = useState(false);
const updateHover = () => {
if (!hover) {
console.log(hover);
setHover(true);
return(0)
} else {
setHover(false)
return;
}
}
as an aside why are you returning from the function? do you need the console.log? a cleaner option would be
const [hover, setHover] = useState(false);
const updateHover = () => setHover(!hover) // flips the current value i.e same as if (hover === true) setHover(false) else setHover(true);
return (
<ThemeProvider theme={ theme }>
<div style={{backgroundColor:'hsl(180, 52%, 96%)',}}>
<div style={{backgroundImage:`url(${headerImage})`, backgroundSize:'cover', height:'10rem'}}></div>
<Box display="flex" justifyContent="center" alignItems="center">
<Box style={{width:'70%', marginTop:'5rem'}}>
<Card style={styles.listing} onMouseEnter={updateHover} onMouseLeave={updateHover}>
<CardActionArea href="#" className="listingHover">
<Listing id="one" hover={hover} />
</CardActionArea>
</Card>
</Box>
</Box>
</div>
</ThemeProvider>
);
}
You are wrong
change state in the React.
Try like this.
const [hover, setHover] = useState(false);
updateHover = () => {
setHover(!hover)
}
or
const [hover, setHover] = useState(false);
return (
<ThemeProvider theme={ theme }>
<div style={{backgroundColor:'hsl(180, 52%, 96%)',}}>
<div style={{backgroundImage:`url(${headerImage})`, backgroundSize:'cover', height:'10rem'}}></div>
<Box display="flex" justifyContent="center" alignItems="center">
<Box style={{width:'70%', marginTop:'5rem'}}>
<Card style={styles.listing} onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}>
<CardActionArea href="#" className="listingHover">
<Listing id="one" hover={hover} />
</CardActionArea>
</Card>
</Box>
</Box>
</div>
</ThemeProvider>
);
I am trying to insert a google maps map in a React application. I would rather not use a non-official library (the ones that I have found lack documentation) and I have already managed inserting the map.
My problem is that the map is re-rendered every time the state of the parent component changes; although the values that change are completely irrelevant from what the map needs.
After a bit of research (I am new to React) I came across the React.memo() HOC which is supposed to prevent re-renders of child components when their props are unchanged. For some reason however I cannot get it to work correctly. Event when I insert the map inside a component with no props, any change in the parent state results in a re-render of the map.
Here is the parent component:
const CompanyDepotsPopup = () => {
const classes = useStyles();
const dispatch = useDispatch();
const open = useSelector((state) => selectIsDepotsPopupOpen(state));
const company = useSelector((state) => selectSelectedCompany(state));
const depotsStatus = useSelector((state) => selectDepotsStatus(state));
const {t} = useTranslation();
const [value, setValue] = useState(0);
const [phone, setPhone] = useState("");
const handleChange = (event, newValue) => {
setValue(newValue);
};
const closeModal = () => {
dispatch(toggleDepotsPopup({}));
}
useEffect(() => {
if (company) {
dispatch(depotsListed({companyId: company.id}));
}
}, [company])
if (!company) return <></>;
if (depotsStatus === "loading") {
return <CenteredLoader/>
}
function TabPanel(props) {
const {children, value, index} = props;
return (
<div
hidden={value !== index}
style={{height: "100%"}}
>
{value === index && (
<Box boxShadow={3} mt={1} ml={2} mr={2} height={"100%"}>
{children}
</Box>
)}
</div>
);
}
return (
<Dialog fullWidth={true} open={open}
aria-labelledby="company-dialog-popup">
<DialogTitle >
{company.name}
</DialogTitle>
<DialogContent style={{padding: 0, margin: 0}}>
<Divider/>
<Box mr={0} ml={0} mt={0} p={0} height="95%">
<div >
<AppBar position="static">
<Tabs value={value} onChange={handleChange} aria-label="depots tabs" centered>
<Tab label={t("Company's depots list")}/>
<Tab label={t("Add new depot")}/>
</Tabs>
</AppBar>
<TabPanel value={value} index={0}>
<DepotsList/>
</TabPanel>
<TabPanel value={value} index={1}>
<Paper>
<Grid container spacing={2}>
<Grid item xs={12} sm={12} md={12} lg={12}>
<TextField
onChange={(event) => setPhone(event.target.value)}
id="phone"
label={t("Phone")}
type="text"
fullWidth
value={phone}
/>
</Grid>
<Grid item xs={12} sm={12} md={12} lg={12}>
<div style={{height: "250px", display: "flex", "flexDirection": "column"}}>
<MyMap
id="myMap"
/>
</div>
</Grid>
<Grid item xs={12} sm={12} md={12} lg={12} align={"center"}>
<Button variant={"outlined"}>
{t("Save")}
</Button>
</Grid>
</Grid>
</Paper>
</TabPanel>
</div>
</Box>
</DialogContent>
<DialogActions style={{marginTop: "20px"}}>
<Button
variant={"outlined"}
onClick={closeModal}
color="secondary"
>
Done
</Button>
</DialogActions>
</Dialog>
)}
And here is the Map component:
import React, {useEffect} from "react";
const Map = ({id}) => {
const onScriptLoad = () => {
const map = new window.google.maps.Map(
document.getElementById(id),
{
center: {lat: 41.0082, lng: 28.9784},
zoom: 8
}
);
const marker = new window.google.maps.Marker({
position: {lat: 41.0082, lng: 28.9784},
map: map,
title: 'Hello Istanbul!'
});
}
useEffect(() => {
if (!window.google) {
const s = document.createElement("script");
s.type = "text/javascript";
s.src = "https://maps.google.com/maps/api/js?key=''"
const x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
s.addEventListener('load', e => {
onScriptLoad();
})
} else {
onScriptLoad();
}
}, []);
return (
<div style={{width: "100%", height: "100%"}} id={id}/>
);
}
const MyMap = React.memo(Map);
export default MyMap;
Every time setPhone is called when the user types the phone and the state changes, the map is re-rendered. Could someone explain to me why the React.memo does not work and how should I proceed in order to avoid re-rendering the map?
I think my guts feeling is this component
function TabPanel(props) {
const {children, value, index} = props;
return (
<div
hidden={value !== index}
style={{height: "100%"}}
>
{value === index && (
<Box boxShadow={3} mt={1} ml={2} mr={2} height={"100%"}>
{children}
</Box>
)}
</div>
);
}
This is defined inside a component, therefore the instance of this component keeps changing after any state change. In order to prevent it, move it outside of the component, like this
function TabPanel()
function CompanyDepotsPopup()
Instead of
function CompanyDepotsPopup() {
function TabPanel()
}
The reason is also your TabPanel wraps everything else.
I got a Sidebar from MaterialUI and I want it to hide on mobile screen, but if you click on the menu icon it should be visible and on big screens it should be visible by default, if you click on the menu icon it should close. I would like to use the library "react-responsive" for this, but I don't understand how to use it.
Sidebar.js
// ...imports and styles..
export const SideBar = ({ open }) => {
const history = useHistory();
return (
<StyledSideBar variant="permanent" open={open}>
<ModuleButton onClick={() => history.push('/dashboard')}>
<Tooltip title="Dashdoard" placement="right" arrow >
<FontAwesomeIcon icon={faTachometerAltFast} />
</Tooltip >
</ModuleButton>
<ModuleButton onClick={() => history.push('/chat')}>
<Tooltip title="Chat" placement="right" arrow>
<FontAwesomeIcon icon={faCommentsAlt} />
</Tooltip>
</ModuleButton>
<ModuleButton onClick={() => history.push('/calendar')}>
<Tooltip title="Calendar" placement="right" arrow>
<FontAwesomeIcon icon={faCalendarAlt} />
</Tooltip>
</ModuleButton>
</StyledSideBar>
);
}
export default SideBar;
MainPage.js
...imports and styles...
export const MainPage = () => {
const dispatch = useDispatch();
const onLogout = () => dispatch(logout());
const [showSidebar, setShowSidebar] = useState(false);
const onToggleSidebar = () => {
setShowSidebar(!showSidebar);
};
const isDesktopOrLaptop = useMediaQuery({
query: '(min-device-width: 1224px)'
})
const isTabletOrMobileDevice = useMediaQuery({
query: '(max-device-width: 1224px)'
})
return (
<>
<MainHeader onLogout={onLogout} onToggleSidebar={onToggleSidebar} />
{isDesktopOrLaptop &&
<SideBar open={showSidebar} />
}
{isTabletOrMobileDevice &&
<SmSideBar open={showSidebar} />
}
<Container>
<BrowserRouter>
<Route path="*" exact component={MainContent} />
</BrowserRouter>
</Container>
</>
);
}
export default authGuardFactory(Redirect)(emailGuardFactory(Redirect)(MainPage));
SmSideBar.js
...import and styles...
export const SmSideBar = ({ open }) => {
const history = useHistory();
return (
<StyledSideBar variant="persistent" open={open} >
<ModuleButton onClick={() => history.push('/dashboard')}>
<Tooltip title="Dashdoard" placement="right" arrow >
<FontAwesomeIcon icon={faTachometerAltFast} />
</Tooltip >
</ModuleButton>
<ModuleButton onClick={() => history.push('/chat')}>
<Tooltip title="Chat" placement="right" arrow>
<FontAwesomeIcon icon={faCommentsAlt} />
</Tooltip>
</ModuleButton>
<ModuleButton onClick={() => history.push('/calendar')}>
<Tooltip title="Calendar" placement="right" arrow>
<FontAwesomeIcon icon={faCalendarAlt} />
</Tooltip>
</ModuleButton>
</StyledSideBar>
);
}
export default SmSideBar;
I tried to add another Sidebar only for Tablet and Mobile, but it dont work.
The only difference between the two is the variant.
I solved the Problem with methods by using react-responsive library and js Breakpoints.
MainPage.js
export const MainPage = ( { match }) => {
const dispatch = useDispatch();
const onLogout = () => dispatch(logout());
const onSizeChange = (matches) => {
setShowSidebar(matches);
}
const isDesktopOrLaptop = useMediaQuery(breakpoints.MAndUp, undefined, onSizeChange)
const [showSidebar, setShowSidebar] = useState(isDesktopOrLaptop);
const onToggleSidebar = () => {
setShowSidebar(!showSidebar);
};
Now everything works fine :)
I am using the continuous slider from metrial-ui in ReactJS project. I want to control the slider such that when click on the play button the slider start moving and stops when clicking stop.below is the code of the slider.
const useStyles = makeStyles({
root: {
width: 200,
},
});
<div className={classes.root}>
<Typography id="continuous-slider" gutterBottom>
Volume
</Typography>
<Grid container spacing={2}>
<Grid item>
<VolumeDown />
</Grid>
<Grid item xs>
<Slider value={value} onChange={handleChange} aria-labelledby="continuous-slider" />
</Grid>
<Grid item>
<VolumeUp />
</Grid>
</Grid>
Thanks in advance
This can be done by calling setState to update the Slider value after an interval. You'll need to use useEffect to create and clean up the interval callback when the isRunning state changes:
export default function ContinuousSlider() {
const [value, setValue] = useState<number>(30);
const [isRunning, setIsRunning] = useState(false);
const directionRef = useRef<"back" | "forward">("back");
const intervalIdRef = useRef(0);
const handleChange = (event: any, newValue: number | number[]) => {
setValue(newValue as number);
};
const handleBack = () => {
directionRef.current = "back";
if (!isRunning) {
setIsRunning(true);
}
};
const handleNext = () => {
directionRef.current = "forward";
if (!isRunning) {
setIsRunning(true);
}
};
const handleStop = () => {
setIsRunning((r) => !r);
};
useEffect(() => {
if (isRunning) {
intervalIdRef.current = setInterval(() => {
if (directionRef.current === "forward") {
setValue((v) => ++v);
}
if (directionRef.current === "back") {
setValue((v) => --v);
}
}, 16);
}
return () => clearInterval(intervalIdRef.current);
}, [isRunning]);
return (
<>
<IconButton onClick={handleStop}>
<StopIcon />
</IconButton>
<IconButton onClick={handleBack}>
<ArrowBackIcon />
</IconButton>
<IconButton onClick={handleNext}>
<ArrowForwardIcon />
</IconButton>
<Slider value={value} onChange={handleChange} />
</>
);
}
Live Demo