I have two seperate components namely Header and Modal. There is a button in Navbar that has an onClick function attached to it. By clicking it the state changes and hence the state is passed to modal as props which then triggers it. The state is then set to false again. However if i click on the button again, the modal does not appear. I have tried many different thing even with useEffects but nothing worked.
Header code
const Header = () => {
const [modal, setModal] = useState(false)
return(
<div>
{modal ? <ModalProduct showModal={true} /> : null}
<ul class="nav navbar-nav ml-auto">
<li><Button variant="danger" style={{ marginTop: '8px' }} onClick={() => setModal(true)}>Add
new product</Button></li></ul>)
</div>)
And for the Modal Component I have
export default function ModalProduct(props) {
const [show, setShow] = useState(props.showModal);
const handleClose = () =>
setShow(false);
return (
< div >
<Modal show={show} onHide={handleClose}>
...
</Modal>
</div >
);
}
There is something related to do with hooks, it gets true for the first time popping the modal and then changes to false but then does not become true again.
Point the onClick to a function that will handle the switching of the state by if true->false and false->true.
const Header = () => {
const [modal, setModal] = useState(false)
const triggerModel = () => {
setModal(!modal)
}
return(
<div>
{modal ? <ModalProduct showModal={triggerModel} /> : null}
<ul class="nav navbar-nav ml-auto">
<li><Button variant="danger" style={{ marginTop: '8px' }} onClick={() => setModal(true)}>Add
new product</Button></li></ul>)
</div>)
You are using 2 states for the same thing (showing/hiding the modal). You only need one state for that. Remove the state from your ModalProduct component and just use the props from your parent component Header to handle the modal. I also refactored your code to make it more concise and readable.
const Header = () => {
const [showModal, setShowModal] = useState(false);
return(
<div>
<ModalProduct showModal={modal} handleClose={()=> setShowModal(false)} />
<ul class="nav navbar-nav ml-auto">
<li>
<Button variant="danger" style={{ marginTop: '8px' }} onClick={()=>setShowModal(true)}>
Add new product
</Button>
</li>
</ul>
</div>
export default function ModalProduct(props) {
return (
<Modal show={props.showModal} onHide={props.handleClose}>
...
</Modal>
);
}
Related
I have some icons from react-icons that I want to change from outline to filled whenever I click it but instead of changing itself, it changes all the icons from outline to filled.
Here is my code
function Header() {
const [isActive, setIsActive] = useState(false);
return (
....
<div className="flex items-center space-x-6">
<div className="cursor-pointer select-none">
{isActive? <AiOutlineHome onClick={()=>{
setIsActive(!isActive)}}/>:
<AiFillHome onClick={()=>{
setIsActive(!isActive)}} />
}
</div>
<div className="cursor-pointer select-none">
{isActive?<MdOutlineAddBox onClick={()=>{
setIsActive(!isActive)}}/>:
<MdAddBox onClick={()=>{
setIsActive(!isActive)}} />}
</div>
....
)}
I know it's because they are sharing the same isActive state, but I don't know exactly how to fix it. Can someone please help me with this?
Edit:
function HeaderIcon({ Icon, ActiveIcon }) {
const [isActive, setIsActive] = useState(false);
return (
<div>{isActive ? <Icon /> : <ActiveIcon />}</div>
);
}
export default HeaderIcon;
I put this component in a new file but how can I pass the onClick to it?
You need to use two different state
function Header() {
const [isActive, setIsActive] = useState(false);
const [isActive2, setIsActive2] = useState(false);
return (
....
<div className="flex items-center space-x-6">
<div className="cursor-pointer select-none">
{isActive? <AiOutlineHome onClick={()=>{
setIsActive(!isActive)}}/>:
<AiFillHome onClick={()=>{
setIsActive(!isActive)}} />
}
</div>
<div className="cursor-pointer select-none">
{isActive2?<MdOutlineAddBox onClick={()=>{
setIsActive2(!isActive2)}}/>:
<MdAddBox onClick={()=>{
setIsActive2(!isActive2)}} />}
</div>
....
)}
I hope this will do magic
The answer for this is:
import React, { useState } from "react";
function HeaderIcon({ inactiveIcon, activeIcon }) {
const [isActive, setIsActive] = useState(false);
return (
<div onClick={() => setIsActive(!isActive)}>
{isActive ? activeIcon : inactiveIcon}
</div>
);
}
export default HeaderIcon;
Then pass in the icon you want.
I have created one custom component, alternative of Select component, on click shows ul and on click hide ul.
when I click I can set value to the state inside function, but i want to access the value in parent component.
so my component is
const [showMenu, setShowMenu] = useState(false);
const [value, setValue] = useState();
return (
<>
<button
className='btn'
onClick={() =>
showMenu ? setShowMenu(false) : setShowMenu(true)
}>
{props.name}
</button>
<ul className={showMenu ? "" : "hide"}>
{props.listsa.map((element) => {
return (
<li
key={element.key}
value={element.value}
onClick={(e) => {
setValue(e.target.value);
}}>
{element.label}
</li>
);
})}
</ul>
</>
I want to access value mentioned above functional component in parent component, which is my app.js
as shown below, this is return method of parent component.
<div className='App'>
{/* <Main /> */}
<OptionsComponent name='ABC Menu' listsa={abc} />
{/* here I want to use that value to perfom operations/ also on change it should show changed value */}
</div>
I tried using localStorage.setItem("value":value) it works but that will use browser memory so I am looking for alternative way.
I tried exporting variable, it shows undefined, also I tried making varibale global, it works but doesnt reflect change.
any help will be appreciated
You just need to bring the state up and pass it down, instead:
const [value, setValue] = useState();
return (
<div className='App'>
{/* <Main /> */}
<OptionsComponent name='ABC Menu' listsa={abc} value={value} setValue={setValue}/>
</div>
And
const [showMenu, setShowMenu] = useState(false);
return (
<>
<button
className='btn'
onClick={() =>
showMenu ? setShowMenu(false) : setShowMenu(true)
}>
{props.name}
</button>
<ul className={showMenu ? "" : "hide"}>
{props.listsa.map((element) => {
return (
<li
key={element.key}
value={element.value}
onClick={(e) => {
props.setValue(e.target.value);
}}>
{element.label}
</li>
);
})}
</ul>
</>
);
In a React project, I have the requirement of opening Modal from another component. I found suggested questions from StackOverflow but, not yet convinced. As I need to make the Modal component reusable across all components. See the code below for reference
Homepage.js
const HomePage = () => {
return (
<>
<button onClick={() => setLoginModalShow(true)}>Open Modal</button>
</>
);
};
I created the below file to export other files too, and make it useful in other components
commonLogin.js
import LoginModal from "./LoginModal";
export const setLoginModalShow = (props) => {
console.log("PROPS", props);
return <LoginModal showModal={props} />;
};
And here is the Modal component
const LoginModal = (props) => {
const [loginModalShow, setLoginModalShow] = useState(props.showModal);
console.log("PROPS in MODAL", props);
return (
<>
<Modal
show={loginModalShow}
onHide={setLoginModalShow}
size="lg"
aria-labelledby="contained-modal-title-vcenter"
centered
>
<Modal.Header closeButton>
<Modal.Title id="contained-modal-title-vcenter">Logout</Modal.Title>
</Modal.Header>
<Modal.Body>
<h4>Are you sure to Logout?</h4>
</Modal.Body>
<Modal.Footer>
<Button onClick={() => setLoginModalShow(false)}>Cancel</Button>
</Modal.Footer>
</Modal>
</>
);
};
Please refer to the code sandbox link: https://codesandbox.io/s/nameless-cdn-70zuq.
After you visit the page click on the 'Open Modal' button
You want to control the show/hide from the parent component
const HomePage = () => {
const [showLogin, setShowLogin] = useState(false);
return (
<>
<button onClick={() => setShowLogin(true)}>Open Modal</button>
<LoginModal show={showLogin} close={() => setShowLogin(false)} />
</>
);
};
<Modal
show={props.show}
cancel={props.close}
...
Here is a working example:
https://codesandbox.io/s/nice-euclid-d0dw0
I am here facing an interesting issue not sure why it is happening.
Basically i have set that for any on click event will trigger the toggleDropDown() which will invert the condition isDropdownOpen (to true or false) and that will help in showing the dropdown menu {isDropdownOpen ? <DropDownlist /> : false}.
I am seeing after 1st click the condition for isDropdownOpen changes to true and thats fine and i click again it changest o false thats fine too but when i do the third click and any later click it remains false, and i can see the elelel remain on the nav bar, any suggestion where i am doing wrong. Thanks
After First click on usericon in navbar ,user-DropdownOpenis set to true
After Second and any later clicks,user-DropdownOpen`remains false
Updated code below &small clip of current status current behaviour of the application
Snippet of Nav.js Component code
import history from "./History";
function Nav({ userinfo, userstatus }) {
const [isDropdownOpen, setDropdownOpen] = useState(false);
const toggleDropDown = (e) => {
e.preventDefault();
history.push("/signin");
return (
<nav className="header">
<label className="logo">
<a href="/">
<img className="yoga-image" src={ProjectLogo} />
</a>
</label>
<ul>
<li>
<a
className="glyphicon glyphicon-shopping-cart
"
href="./basket"
></a>
</li>
<li>
<a className="active" href="./signin">
{userstatus ? (
<button
style={{ border: "none", background: "none", outline: "none" }}
className=" signin-icon glyphicon glyphicon-user
"
onClick={(e) => toggleDropDown(e)}
></button>
) : (
<button style={{ border: "none", background: "none", outline: "none" }} onClick={(e) => toggleDropDown(e)}>
SIGNIN
</button>
)}
</a>
</li>
</ul>
{isDropdownOpen && <DropDownlist />}
</nav>
);
}
Snippet of History.js Component code
import { createBrowserHistory } from "history";
export default createBrowserHistory();
Snippet of App.js Component code
```
import Signin from "./Component/Signin";
import history from "./History";
return (
<Router history={history}>
<div className="App">
<header className="header">
<Nav userinfo={userData} userstatus={siginalready} />
</header>..................
<Switch> // here we got switch statement contains(/,/basket,/signin)
<Route
path="/"
exact
render={(props) => <Home {...props} userData={userData} userstatus={siginalready} addBasketitems={addBasketitems} />}
/>
<Route
path="/basket"
exact
render={(props) => (
<Basket {...props} userData={userData} userstatus={siginalready} basketItems={basketItems} updatedBasket={updatedBasket} resetBasket={resetBasket} />
)}
/>
<Route
path="/signin"
exact
render={(props) => <Signin {...props} buyNow={buyNow} resetBuynow={resetBuynow} userData={userData} finalBuy={finalBuy} userstatus={siginalready} />}
/>
<div className="footer">
<Footer />
</div>
</div>
</Router>
);
Snippet of Signin.js Component code
function Signin({ userData, userstatus, finalBuy, buyNow, resetBuynow }) {
//POST request to server...................and recieve Invoices
return <div>{userstatus ? <Useraccount userinfo={userData} userstatus={userstatus} finalBuy={finalBuy} allInvoices={allInvoices} /> : <SigninOptions />}</div>;
}
export default Signin;
Try setting initial state to false instead of getting it from the localStorage, so that its closed in the beginning (I suspect that this might be your issue, since when you set the state its already in the local storage and you will never get a false again as an initial condition, unless the storage is set to false):
const [isDropdownOpen, setDropdownOpen] = useState(false);
Then when you are setting the state in the toggle function do:
setDropDownOpen(prevState => return { !prevState });
When you change a state of a component, you have to use the previous state to do that (might not be the actual issue that you are having, its just a good practice).
Then at the end of your function where you are rendering the DropDownList change it to:
{isDropDownOpen && <DropDownList />}
This is something like a "binary operator" so it will render DropDownList only if isDropDownOpen is true, otherwise it will not do anything.
I am suspecting that the issue might have to do something with the function that you made initialDropDownOpen(), see if the above changes fix it.
P.S. You can implement the changes one by one and see which if any of them fixes it :) and please let me know! :)
EDIT: Lift the state up, move
const [isDropdownOpen, setDropdownOpen] = useState(false);
into the parent component and then add a property to your dropDown, for example call it show, so:
<Nav show={isDropDownOpen} toggle={setDropdownOpenWrapper} ...otherprops.../>
You have to wrap the set function and pass the wrapped function:
const setDropdownOpenWrapper = () => { setDropDown(prevState => return { !prevState}) };
and then use show and toggle inside the Nav component.
It is happening due to tag have event attribute. When you click it, it tries to send form attached to it as default and redirect url or main domain. What you can do is simple. just using
e.preventDefault()
You need to update onClick and toggleDropDown functions like following
onClick;
{userstatus ? (
<button
style={{ border: "none", background: "none", outline: "none" }}
className=" signin-icon glyphicon glyphicon-user "
onClick={e => toggleDropDown(e)}
></button>
) : (
<button
style={{ border: "none", background: "none", outline: "none" }}
onClick={e => toggleDropDown(e)}
>
SIGNIN
</button>
)}
toggleDropDown;
const toggleDropDown = e => {
e.preventDefault();
setDropdownOpen(prevState => !prevState);
};
with these updates it will stay at your component or will not refresh the page or will not try to render your component again.
Also for localStorage you can use useEffect to update state.
define your state false/true as default, then write a useEffect hook.
useEffect(() => {
if (localStorage.getItem("test")) {
setDropdownOpen(localStorage.getItem("test"));
}
}, []);
I'm trying to do a sidebar that hides on the clicking of an icon in the navigation bar. And I don't want to use classes, maybe I'm wrong doing it this way, but I want to keep it as much as possible. I've got an error that says:
(property) collapsed: boolean ';' expected.ts(1005)
In the const toggle:
const state = {
collapsed: true
};
const toggle = () => {
state.collapsed: !state.collapsed
};
const Sidebar = () => {
return (
<Layout.Sider collapsed={state.collapsed} style={{ backgroundColor: '#f0f0f0' }}>
...
</Layout.Sider>
)
}
In the navigation bar I got this:
<Button
type="primary"
shape="circle"
icon="user"
size={'small'}
style={{ marginLeft: '10px' }}
onClick={() => toggle}
/>
My layout:
const Layout = ({ children }: LayoutProps) => {
return (
<AntdLayout>
<AntdLayout>
<Header />
</AntdLayout>
<div>{children}</div>
<Sidebar />
</AntdLayout>
)
}
Thank you all!
There are two things what I found as an issue in your code. If you have functional component, you can use useState for updating boolean state. The other one is how you use onClick={() => toggle}, technically you are not calling the function, just returning.
I think you can try the following - creating a boolean variable with state hook:
const Sidebar = () => {
const [collapsed, setCollapsed] = useState(true);
return (
<Layout.Sider collapsed={state.collapsed} style={{ backgroundColor: '#f0f0f0' }}>
...
</Layout.Sider>
)
}
And in the button, you can use as the following - toggling the value of collapsed variable:
<Button type="primary"
shape="circle"
icon="user"
size={'small'}
style={{ marginLeft: '10px' }}
onClick={() => setCollapsed(!collapsed)} />
Read further here:
State hook
Function and Class components
If you are interested in further, I have prepared earlier a repository on GitHub to present toggling elements in class, functional or styled components. Find it here: norbitrial/react-toogle-class-on-click
I hope this helps!