Uncaught TypeError: isOpen is not a function - javascript

I was trying to convert my class-based component to function based component, which I wrote some while when I was learning REACT, while converting this, I got an error that isOpen is not the function which I kinda dint get as I defined it as a state and called in handleToggle(), which is then being called at the logo of my component.
import React, { useState, useEffect } from "react";
import logo from "../images/logo.svg";
import { FaAlignRight } from "react-icons/fa";
import { Link } from "react-router-dom";
import Badge from '#mui/material/Badge';
import Menu from '#mui/material/Menu';
import MenuItem from '#mui/material/MenuItem';
export default function Navbar(){
const [anchorEl, setAnchorEl] = useState(null);
const open = Boolean(anchorEl);
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const [isOpen, setIsOpen] = useState(null);
useEffect(() =>{
handleToggle();
});
// state = {
// isOpen: false,
// };
const handleToggle = () => {
setIsOpen(isOpen() );
};
return (
<nav className="navbar">
<div className="nav-center">
<div className="nav-header">
<Link to="/">
<img src={logo} alt="Beach Resort" />
</Link>
<button
type="button"
className="nav-btn"
onClick={handleToggle}
>
<FaAlignRight className="nav-icon" />
</button>
</div>
<ul
className={isOpen ? "nav-links show-nav" : "nav-links"}
>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/rooms">Rooms</Link>
</li>
</ul>
<Badge badgeContent={4} color="primary"
id="basic-button"
aria-controls={open ? 'basic-menu' : undefined}
aria-haspopup="true"
aria-expanded={open ? 'true' : undefined}
onClick={handleClick}
>
<i className="fa-solid fa-cart-shopping text-light"
style={{ fontSize: 25, cursor: "pointer" }}
></i>
</Badge>
</div>
<Menu
id="basic-menu"
anchorEl={anchorEl}
open={open}
onClose={handleClose}
MenuListProps={{
'aria-labelledby': 'basic-button',
}}
>
<MenuItem onClick={handleClose}>Profile</MenuItem>
<MenuItem onClick={handleClose}>My account</MenuItem>
<MenuItem onClick={handleClose}>Logout</MenuItem>
</Menu>
</nav>
);
}
EVERY PIECE OF ADVICE WILL BE APPRECIATED

useState returns an array with two things: a value that is stored in state, and a function to update it. If you call const [isOpen, setIsOpen] = useState(null), isOpen is your value (originally set as null) and setIsOpen is a function to update it.
When you write const handleToggle = () => { setIsOpen(isOpen() ) }, you're trying to call a null value, which is impossible because it's not a function. That's what the error message is telling you.
Given you want to toggle the value for isOpen, what you should do instead is declare isOpen as a boolean, and call setIsOpen with the opposite of isOpen:
const [isOpen, setIsOpen] = useState(false); // <= set this originally to false
const handleToggle = () => {
setIsOpen(!isOpen); // <= this will set isOpen as true when it is false, and false when it is true
};
However, if you call handleToggle inside a useEffect with no dependency array, like you're doing, it will be called every time there is a rerender, which is probably not what you want. You most likely want to call this in response to a user interaction - so in response to an HTML element event (like onClick). Otherwise you should refactor your code to add the necessary dependencies to useEffect.

isOpen contains value, not a function,try this setIsOpen(p => !p)

Related

React style object not being applied

Having issues with React style not being applied. I have no idea why it is not working as it was before.
See code below:
Accordion.js
import React, {useState} from 'react'
import { risk_assessment } from '../data/questions';
import AccordionItem from '../components/AccordionItem';
import Question from '../components/Question';
const Accordion = props => {
const [active, setActive] = useState("0")
return (
<ul className="accordion">
{risk_assessment.map((question, index) => (
<AccordionItem
key={index}
itemTitle={question.question}
itemContent={<Question options={question.options} name={question.name} />}
toggle={() => setActive(index)}
active={active == index} />
))}
</ul>
)
}
export default Accordion
AccordionItem.js
import React, {useRef, useEffect} from 'react'
const AccordionItem = ({ itemTitle, itemContent, toggle, active }) => {
const accordionContent = useRef()
let contentHeight = {}
useEffect(() => {
contentHeight = active ? {height: accordionContent.current.scrollHeight} : {height: "0px"}
})
return (
<li className="accordion_item">
<button className="button" onClick={toggle}>
{itemTitle}
<span className="control">{active ? "—" : "+"}</span>
</button>
<div className="answer_wrapper" ref={accordionContent} style={contentHeight} >
<div className="answer">{itemContent}</div>
</div>
</li>
)
}
export default AccordionItem
Question.js simply renders the data inside the Accordion Item.
Here is the output from Chrome developer tools.
I have tried messing with the useEffect hook to no success. Changed it to run on every render, only on the first render, added the ref as a dependency etc.
I need to use the useRef hook to get the height of the content area dynamically.
Any help would be appreciated.
In your case when the component re-renders the value of your variable will be lost. Try putting contentHeight in a state.
const [contentHeight, setContentHeight] = useState({})
useEffect(() => {
setContentHeight(active ? {height: accordionContent.current.scrollHeight} : {height: "0px"});
}, [active])
You can find more information in this post.

React - Access the state of a parent from the children, without nested function

Hello,
I am coming to you today for the first time because I have not found a solution to my problem.
I have been using react for a few weeks, Don't be too cruel about the quality of my code 😁.
Problem :
I am looking to access the state of a parent from their children.So I want to be able to access the setHeight function and the height variable for example from a child component.
Please note :
However, to keep some flexibility, I don't want to have any Components inside our.
I looked at redux to be able to do this, but the problem is that the data is global so creating multiple dropdowns would not be possible.
(Unless I didn't understand too much, redux is quite complex)
Diagram :
I have created a diagram to explain it a little better.,
I'd like the children of DropdownMenu to be able to access the state of the latter, Also, the different Dropdowns must have their own state independently.
So ideally I want to keep the same structure as find very flexible, and the possibility to create several dropdown.
Code :
I Share my four components :
export default function Navbar () {
return (
<nav className={styles.navbar}>
<ul className={styles.navbarNav}>
<NavItem icon={<NotificationsIcon />} />
<NavItem icon={<AccessTimeFilledIcon />} />
<NavItem icon={<FileOpenIcon />}>
<DropdownMenu>
<DropdownSubMenu menuName="Home">
<DropdownItem>My Profile</DropdownItem>
<DropdownItem leftIcon={<AccessTimeFilledIcon />} rightIcon={<ChevronRightIcon />} goToMenu="pages">Pages</DropdownItem>
<DropdownItem>IDK</DropdownItem>
<DropdownItem>Test</DropdownItem>
</DropdownSubMenu>
<DropdownSubMenu menuName="pages">
<DropdownItem>Pages</DropdownItem>
<DropdownItem leftIcon={<AccessTimeFilledIcon />} rightIcon={<ChevronRightIcon />} goToMenu="home">Home</DropdownItem>
</DropdownSubMenu>
</DropdownMenu>
<DropdownMenu>
<DropdownSubMenu menuName="config">
<DropdownItem>Foo</DropdownItem>
<DropdownItem leftIcon={<AccessTimeFilledIcon />} rightIcon={<ChevronRightIcon />} goToMenu="theme">Configuration</DropdownItem>
<DropdownItem>Bar</DropdownItem>
<DropdownItem>Baz</DropdownItem>
</DropdownSubMenu>
<DropdownSubMenu menuName="theme">
<DropdownItem>Hi StackOverflow</DropdownItem>
<DropdownItem leftIcon={<AccessTimeFilledIcon />} rightIcon={<ChevronRightIcon />} goToMenu="config">Theme</DropdownItem>
</DropdownSubMenu>
</DropdownMenu>
</NavItem>
</ul>
</nav>
);
};
type Props = {
children?: React.ReactNode | React.ReactNode[];
leftIcon?: React.ReactNode | JSX.Element | Array<React.ReactNode | JSX.Element>;
rightIcon?: React.ReactNode | JSX.Element | Array<React.ReactNode | JSX.Element>;
goToMenu?: string;
goBack?: boolean;
OnClick?: () => void;
};
export default function DropdownItem({ children, leftIcon, rightIcon, goToMenu, goBack, OnClick }: Props) {
const handleClick = OnClick === undefined ? () => { } : OnClick;
return (
<a className={styles.menuItem} onClick={() => {
goToMenu && setActiveMenu(goToMenu);
setDirection(goBack ? 'menu-right' : 'menu-left');
handleClick();
}}>
<span className={styles.iconButton}>{leftIcon}</span>
{children}
<span className={styles.iconRight}>{rightIcon}</span>
</a>
);
}
type Props = {
menuName: string;
children: React.ReactNode | React.ReactNode[];
}
enum Direction {
LEFT = 'menu-left',
RIGHT = 'menu-right'
}
export default function DropdownSubMenu (props: Props) {
const [direction, setDirection] = useState<Direction>(Direction.LEFT);
const calcHeight = (element: HTMLElement) => {
if (element) setMenuHeight(element.offsetHeight);
};
return (
<CSSTransition in={activeMenu === props.menuName} unmountOnExit timeout={500} classNames={direction} onEnter={calcHeight}>
<div className={styles.menu}>
{props.children}
</div>
</CSSTransition>
);
}
type Props = {
children: React.ReactNode | React.ReactNode[];
}
export default function DropdownMenu (props: Props) {
const [activeMenu, setActiveMenu] = useState<string>('home');
const [menuHeight, setMenuHeight] = useState<number | null>(null);
const dropdownRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const child = dropdownRef.current?.firstChild as HTMLElement;
const height = getHeight(child);
if (height)
setMenuHeight(height);
}, []);
return (
<div className={styles.dropdown} style={{ height: `calc(${menuHeight}px + 2rem)` }} ref={dropdownRef}>
{props.children}
</div>
);
}
Conclusion :
More concretely I don't know what to put instead :
In DropdownSubMenu to set the menu height (setMenuHeight), and gets the active menu (activeMenu).
In DropdownItem, set the active menu, (setActiveMenu) and set the direction of the CSS animation (setDirection).
Source :
My code is adapted from these sources, But I want to make this code more professional, flexible and polymorphic :
https://github.com/fireship-io/229-multi-level-dropdown
I've been tried :
I tried to look at Redux, but I understood that it was only state global.
So it doesn't allow to define a different context for each component.
I tried to look at React 18, without success.
I have searched the StackOverflow posts, I have searched the state retrieval from the parents.
The use of components inside a component solves in effect the problem but we lose all the flexibility.
There are multiple ways to access a parent state from its children.
Pass the state as props
The preferred way is to pass the state and/or the change function to the children.
Example :
const App = () => {
const [open, setOpen] = React.useState(false);
const handleOpen = () => setOpen(true);
const handleClose = () => setOpen(false);
return (
<div>
<button onClick={handleOpen}>Open modal</button>
<Modal onClose={handleClose} open={open} />
</div>
);
};
const Modal = ({ open, onClose }) => (
<div className={open ? "open" : "close"}>
<h1>Modal</h1>
<button onClick={onClose}>Close</button>
</div>
);
ReactDOM.render(<App />, document.querySelector("#app"));
Demo: https://jsfiddle.net/47s28ge5/1/
Use React Context
The first method becomes complicated when the children are deeply nested and you don't want to carry the state along the component tree.
You can then share a state across multiple children by using context.
const AppContext = React.createContext(undefined);
const App = () => {
const [open, setOpen] = React.useState(false);
const handleOpen = () => setOpen(true);
const handleClose = () => setOpen(false);
return (
<AppContext.Provider value={{ open, onClose: handleClose }}>
<div>
<button onClick={handleOpen}>Open modal</button>
<Modal />
</div>
</AppContext.Provider>
);
};
const Modal = () => {
const { open, onClose } = React.useContext(AppContext);
return (
<div className={open ? "open" : "close"}>
<h1>Modal</h1>
<button onClick={onClose}>Close</button>
</div>
);
};
ReactDOM.render(<App />, document.querySelector("#app"));
Demo: https://jsfiddle.net/dho0tmc2/3/
Using a reducer
If your code gets even more complicated, you might consider using a store to share a global state across your components.
You can take a look at popular options such as:
Mobx: https://mobx.js.org/ (my personal favorite)
Redux: https://redux.js.org/
RxJS: https://rxjs.dev/
I can say welcome to react in this moment and i glad for you
OK, i could understand what is your problem.
but there isn't problem and this bug cause from your low experience.
As i understand you want to click on a dropdown and open it.
and here we have nested dropdown.
I think it's your answer:
You should declare a state on each dropdown and don't declare state in parent.

Close Hamburger Menu When mobile menu Link is clicked

when I click the menu item the page loads but the menu stays open.
this is the Mobile Menu it JSX:
const MobileMenu = () => {
const navigation = [
{ link: '/applications', text: 'Applications' },
{ link: '/multi-media', text: 'Media' },
{ link: '/websites', text: 'Websites' },
{ link: '/mobile-apps', text: 'Mobile' },
{ link: '/support', text: 'Support' },
{ link: '/contact', text: 'Contact' },
{ link: '/', text: 'Login' },
];
return (
<NavMenuContainer>
<NavList>
<div className="flex pb-4 lg:px-6 lg:hidden">
<Searchbar id="mobile-search" />
</div>
{navigation.map(nav => (
<NavLink key={nav.text}>
<Link href={nav.link}><a>
{nav.text}
</a></Link>
</NavLink>
))}
</NavList>
</NavMenuContainer>
);
};
export default MobileMenu
this is NAV the MobileMenu menu is in(JSX:
export default function HamburgerMenu(props) {
const [isOpen, setOpen] = useState(false);
//change
const toggleMenu = () => {
let dd = document.body;
dd.classList.toggle("navbar-mobile");
setOpen(!isOpen);
};
return (
<Theburger>
<HamburgerMenuContainer>
<MenuToggle toggle={toggleMenu} isOpen={isOpen} />
<MenuContainer
initial={false}
animate={isOpen ? "open" : "closed"}
variants={menuVariants}
transition={menuTransition}
>
<ContentContainer>
<MobileMenu isOpen={isOpen} />
</ContentContainer>
</MenuContainer>
</HamburgerMenuContainer>
</Theburger>
);
}
this is the website main menu it TSX:
const Navbar: FC<NavbarProps> = ({ links }) => (
<NavbarRoot>
<Container>
<div className={s.nav}>
<div className="flex items-center">
<Link href="/"><a>
<div className="logo">
<Image width={106} height={27} src="/logo.svg" alt="brand" />
</div>
</a></Link>
<nav className={s.navMenu}>
{[...links3 ].map((page) => (
<span key={page.url}>
<Link href={page.url!}>
<a className={s.link}>
{page.name}
</a>
</Link>
</span>
))}
{links?.map((l) => (
<Link href={l.href} key={l.href}>
<a className={s.link}>{l.label}</a>
</Link>
))}
</nav>
</div>
<div className="flex items-center justify-end flex-1 space-x-8 mr-5">
<UserNav />
</div>
<div className="flex items-center justify-end flex-2">
<Nav />
</div>
</div>
</Container>
</NavbarRoot>
)
export default Navbar
Its a nextjs app Im using a Layout component in _app.tsx not sure if that matters but it really shouldn't, I Missed tsx with jsx and according to the docs at NextJS and javascript in general mixing them shouldn't cause problems.
You're missing to give the state as a prop to your toggle menu function.
Thus isOpen is always false and the state gets changed always to true.
Change your toggleMenu() to toggleMenu(isOpen) and it's fine.
export default function HamburgerMenu(props) {
const [isOpen, setOpen] = useState(false);
//change
const toggleMenu = (myState) => {
let dd = document.body;
dd.classList.toggle("navbar-mobile");
setOpen(!isOpen);
};
return (
<Theburger>
<HamburgerMenuContainer>
<MenuToggle toggle={()=>toggleMenu(isOpen)} isOpen={isOpen} />
<MenuContainer
initial={false}
animate={isOpen ? "open" : "closed"}
variants={menuVariants}
transition={menuTransition}
>
<ContentContainer>
<MobileMenu isOpen={isOpen} />
</ContentContainer>
</MenuContainer>
</HamburgerMenuContainer>
</Theburger>
);
}
The reason you're running into the menu being always visible, is because when react compiles the function, the initial value is used whether it was changed or not. Resulting in the following function to always console log "initial" even when the state has changed.
function A() {
const [textState, setTextState] = useState('initial');
const printState = () => {
console.log(textState);
setTextState('changed');
}
return <button onClick={()=>printState()}>Print me</button>
}
this behaves different in the following two scenarios where either the state is from the parent or the props are given to the function.
Parent Props
function B({textState, setTextState}) {
const printState = () => {
console.log(textState);
setTextState('changed');
}
return <button onClick={()=>printState()}>Print me</button>
}
In function B the printState function is given as a prop and the function is rerendered when the props change, causing also the printState function to be compiled again with the new props causing to console log changed instead of initial.
The other option is handling the state in the component itself and giving the state as a prop to our function.
function C() {
const [textState, setTextState] = useState('initial');
const printState = (prop) => {
console.log(prop);
setTextState('changed');
}
return <button onClick={()=>printState(textState)}>Print me</button>
}
Here the prop is given directly to the printState function, while the printState function is not being recompiled the updated state is given as a prop and handled accordingly

Share State between two specific instances of the same react component React

Before y'all say global state(redux), I'd like to say one thing. I'm mapping through an array I fetched from my API. I receive images and map over them and render my Slider component. Every 2 sliders must share the same state. So, then if i move to the next slide in the first slider, then the second slider must also go to the next slide(but not any other slides). If I move to the next slide in the 5th slider, the 6th must also move to the next slide... so on.
Component where I map over slides:
<div className='image-grid'>
{screenshots.map((imagesByResolution, resIdx, screenshotResArr) => {
return imagesByResolution.map((img, scriptIdx, screenshotScriptsArr) => {
return <Slider slides={formattedSlides} />;
});
})}
</div>
Slider:
import Button from '#material-ui/core/Button';
import MobileStepper from '#material-ui/core/MobileStepper';
import { useTheme } from '#material-ui/core/styles';
import KeyboardArrowLeft from '#material-ui/icons/KeyboardArrowLeft';
import KeyboardArrowRight from '#material-ui/icons/KeyboardArrowRight';
import React from 'react';
import SwipeableViews from 'react-swipeable-views';
import { autoPlay } from 'react-swipeable-views-utils';
import { encodeImage } from '../services/images';
import useStyles from '../styles/slider';
const AutoPlaySwipeableViews = autoPlay(SwipeableViews);
export interface ISlide {
title: string;
img: ArrayBuffer;
}
interface Props {
slides: ISlide[];
}
export default function Slider(props: Props) {
console.log(props);
const { slides } = props;
const classes = useStyles();
const theme = useTheme();
const [activeSlide, setActiveSlide] = React.useState(0);
const maxSlides = slides.length;
const handleNext = () => {
setActiveSlide((prevActiveStep) => prevActiveStep + 1);
};
const handleBack = () => {
setActiveSlide((prevActiveStep) => prevActiveStep - 1);
};
const handleSlideChange = (step: number) => {
setActiveSlide(step);
};
return (
<div className={classes.root}>
<div className={classes.header}>
<h4 className={classes.title}>{slides[activeSlide].title}</h4>
</div>
<AutoPlaySwipeableViews
axis={theme.direction === 'rtl' ? 'x-reverse' : 'x'}
index={activeSlide}
onChangeIndex={handleSlideChange}
enableMouseEvents
>
{slides.map((slide, index) => (
<div key={index}>
{Math.abs(activeSlide - index) <= 2 ? (
<img className={classes.img} src={encodeImage(slide.img, 'image/png')} alt={slide.title} />
) : null}
</div>
))}
</AutoPlaySwipeableViews>
<MobileStepper
steps={maxSlides}
position='static'
variant='text'
activeStep={activeSlide}
nextButton={
<Button size='small' onClick={handleNext} disabled={activeSlide === maxSlides - 1}>
Next
{theme.direction === 'rtl' ? <KeyboardArrowLeft /> : <KeyboardArrowRight />}
</Button>
}
backButton={
<Button size='small' onClick={handleBack} disabled={activeSlide === 0}>
{theme.direction === 'rtl' ? <KeyboardArrowRight /> : <KeyboardArrowLeft />}
Back
</Button>
}
/>
</div>
);
}
If this is not possible using either some global state management library or plain ol' react state, what is the other alternative? Thanks in advance!
Pass a unique key prop to each instance of your component.
Credits: https://stackoverflow.com/a/65654818/9990676

Callback to control modal display

I have built a modal to display login/register modal. By default, the modal is opened by another component using the props show. This working when the modal is called by this component.
Also the modal Form is called from my Header.js as shown below:
<LoginRegisterForm displayPopUp={this.state.showLogin} onHide={() => this.setState({ showLogin: false })}/>}
In this case, the state showLogin is set to true when clicking on the Login/Register, the <LoginRegisterform is now showing the modal because displayPopup props is set to true
The code is below:
Form.js
const Form = ({ initialState = STATE_SIGN_UP, displayPopUp}) => {
const [mode, toggleMode] = useToggle(initialState);
const [display, toggleDisplay] = useToggleDisplay(displayPopUp);
console.log('----------------------------------------------------------')
console.log('displayPopUp: ' + displayPopUp)
console.log('display: ' + display)
console.log('toggleDisplay: ' + toggleDisplay)
console.log('----------------------------------------------------------')
return (
<Modal className="modal" show={displayPopUp} size="lg">
<Container pose={mode === STATE_LOG_IN ? "signup" : "login"}>
<div className="container__form container__form--one">
<FormLogin mode={mode} toggleDisplay={toggleDisplay} />
</div>
<div className="container__form container__form--two">
<FormSignup mode={mode} toggleDisplay={toggleDisplay}/>
</div>
<Overlay toggleMode={toggleMode} mode={mode} />
</Container>
</Modal>
);
};
in the FormLogin, I do have a Cancel button which allow me to close the modal located in the Form.js when needed. However, I do not know how I can make the modal close by change the show params in the Form.js when the close control is in the class FormLogin
FormLogin.js
import React from 'react'
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
import SocialButton from './styled/SocialButton'
import SlidingForm from './styled/SlidingForm'
import WhiteButton from '../../materialdesign/WhiteButton'
import { faFacebook, faGoogle, faLinkedinIn } from '#fortawesome/free-brands-svg-icons'
import Auth from '../../../data/network/Auth';
import Constant from '../../../config/Constant';
import CancelIcon from '#material-ui/icons/Cancel';
class FormLogin extends React.Component {
constructor(props, context) {
super(props);
this.state = {
email: '',
password: '',
loading: false,
error: '',
toggleDisplay: this.props.toggleDisplay
};
}
requestSignIn = async (event) => {
event.preventDefault();
this.setState({loading: true})
try {
const authData = await Auth.getToken(`${this.state.email}`, `${this.state.password}`);
sessionStorage.setItem(Constant.ALL, authData)
sessionStorage.setItem(Constant.AUTH_TOKEN, authData.token)
sessionStorage.setItem(Constant.DISPLAY_NAME, authData.user_display_name)
sessionStorage.setItem(Constant.EMAIL, authData.user_email)
sessionStorage.setItem(Constant.NICENAME, authData.user_nicename)
window.open("/", "_self") //to open new page
this.setState({loading: false })
this.close()
} catch (error) {
console.warn("Connection to WP - Auth Token failed ")
console.error(error);
}
}
requestForgotPassword = () => {
}
handleOnChange = (event) => {
this.setState({[event.target.name]: event.target.value})
}
render(){
const { email, password } = this.state;
return(
<SlidingForm>
<div style={{textAlign:"left"}}>
<CancelIcon style={{ color: "#ff7255" }} onClick={() => this.state.toggleDisplay(false) }/>
</div>
<h1 style={titleStyle}>Sign in</h1>
<div style={{textAlign: "center"}}>
<SocialButton>
<FontAwesomeIcon icon={faFacebook} />
</SocialButton>
<SocialButton>
<FontAwesomeIcon icon={faGoogle} />
</SocialButton>
<SocialButton>
<FontAwesomeIcon icon={faLinkedinIn} />
</SocialButton>
</div>
<p style={txtStyle}>or use your account</p>
<form style={{textAlign: "center"}}>
<input style={formStyle} placeholder="Email" type="text" name="email" value={ email } onChange={ this.handleOnChange }/>
<input style={formStyle} placeholder="Password" type="password" name="password" value={ password } onChange={ this.handleOnChange } />
</form>
<p style={txtSpan}>
<a href="#" onClick={this.requestForgotPassword}>Forgot your password?</a>
</p>
<div style={{textAlign: "center", marginTop: "15px"}}>
<WhiteButton text="Sign in" onClick={this.requestSignIn}></WhiteButton>
</div>
</SlidingForm>
);
}
}
export default FormLogin
For now I was doing this :
<CancelIcon style={{ color: "#ff7255" }} onClick={() => this.state.toggleDisplay(false)
but it's not working, it's seems not having control on the Form.js.
toggleDisplay code is below:
import { useState } from 'react'
export const STATE_SHOW = true
export const STATE_HIDE = false
const useToggleDisplay = initialDisplayState => {
const [display, setDisplay] = useState(initialDisplayState)
const toggleDisplay = () =>
setDisplay(display === false ? true : false)
console.log('-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%')
console.log('display: ' + display)
console.log('toggleDisplay: ' + toggleDisplay)
console.log('-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%')
return [display, toggleDisplay]
}
export default useToggleDisplay
The Overall logic:
Modal is called from Header.js and show is set to false by default and switch to true when clicking on the menu option login
The Modal Form.js is handling login and register screen
What is the best option to be able to set show to false in the Form.js when the close is triggered in the FormLogin.js ?
Thanks
Instead of assigning the toggleDisplay prop to local state, just invoke the prop directly. This should work for updating the <Form />'s display state to false.
Also, do you intend for the <CancelIcon /> to toggle the modal open/close state, or is it just to close the modal? If it's the latter, you may want to update the prop name to closeModal instead of toggleDisplay.
<div style={{textAlign:"left"}}>
<CancelIcon style={{ color: "#ff7255" }} onClick={() => this.props.toggleDisplay(false)
}/>
</div>
Your useToggleDisplay func is confusing, and the original version was not accepting any arguments for toggleDisplay, hence even though you passed in false, it did not update the display state. I've removed useToggleDisplay since it doesn't do anything special.
const [display, setDisplay] = useState(initialDisplayState)
I also realised that <Modal /> is accepting displayPopUp instead of display. If you use displayPopUp, it doesn't know that display has been set to false, and therefore, remain open. And I passed setDisplay setter to the <FormLogin /> components.
<Modal className="modal" show={display} size="lg">
<Container pose={mode === STATE_LOG_IN ? "signup" : "login"}>
<div className="container__form container__form--one">
<FormLogin mode={mode} toggleDisplay={setDisplay} />
</div>
<div className="container__form container__form--two">
<FormSignup mode={mode} toggleDisplay={setDisplay}/>
</div>
<Overlay toggleMode={toggleMode} mode={mode} />
</Container>
</Modal>

Categories