Comments (37)
I would like to work on this issue, can you please assign it to me?
assigned to you @sumitshinde-84
from react.
Also a quick suggestion @RahulMittal18 please use conditional rendering instead of styles rendering. Its always better to not mount the required elements/nodes into the DOM tree which makes things less expensive on rendering side. Just dropping in a suggestion
const Navbar = () => {
const [isOpen, setIsOpen] = useState(false);
const imgRef = useRef();
const handleImageClick = () => {
setIsOpen((prevIsOpen) => !prevIsOpen);
};
useEffect(() => {
const handleClickOutside = (evt) => {
if (imgRef?.current && !imgRef?.current?.contains(evt.target)) {
setIsOpen(false);
}
};
document.addEventListener("click", handleClickOutside);
// cleanup for event listener
return () => {
document.removeEventListener("click", handleClickOutside);
};
}, [isOpen]);
return (
<>
{isOpen && (
<div className={"dropdown"}>
<Dropdown />
</div>
)}
<div className="profile_icon_div" ref={imgRef} onClick={handleImageClick}>
<img
src={profileImageUrl}
onClick={() => setIsOpen((prev) => !prev)}
className="profile_icon_image"
alt="Profile-Icon"
/>
</div>
</>
);
};
You can also create a custom hook where you can pass the ref and your callback method which can manage the click events which are clicked outside the ref which you pass in the hook.
Happy Learning 😊
from react.
you can use the elseif for targeting the same icon when dropdown is active
useEffect(() => {
let closeDropdown = (e) => {
if (imgRef.current && !imgRef.current.contains(e.target)) {
setIsOpen(false);
} else if (imgRef.current === e.target) {
setIsOpen((prev) => !prev);
}
};
document.body.addEventListener("click", closeDropdown);
return () => document.body.removeEventListener("click", closeDropdown);
}, []);
from react.
Still not working @Animesh239
from react.
useEffect(() => {
let closeDropdown = (e) => {
if (imgRef.current && !imgRef.current.contains(e.target)) {
setIsOpen(false);
}
};
document.body.addEventListener("click", closeDropdown);
return () => document.body.removeEventListener("click", closeDropdown);
}, [isOpen]);
// there I added [isOpen] in the dependency array of useEffect
// whenever isOpen will change useEffect will be called with its sideeffect
// I think it will work.
.
.
.
.
// And yeah one more thing is that , there is an extra div tag
return (
<div>
<div>
<div className={"dropdownn1 " + (isOpen ? "open" : "closed")}>
<Dropdown />
</div>
<div className="profile_icon_div" ref={imgRef}>
<img
src={profileImageUrl}
onClick={() => setIsOpen((prev) => !prev)}
className="profile_icon_image"
alt=""
/>
</div>
</div>
);
from react.
Still not working guys @Animesh239 @iRONiCBAT7 . Ignore extra div, there is no extra div in the real code. It just got extra here in copying.
my updated useEffect which is not working stll:
useEffect(() => {
let closeDropdown = (e) => {
if (imgRef.current && !imgRef.current.contains(e.target)) {
setIsOpen(false);
} else if (imgRef.current === e.target) {
setIsOpen((prev) => !prev);
}
};
document.body.addEventListener("click", closeDropdown);
return () => document.body.removeEventListener("click", closeDropdown);
}, [isOpen]);
from react.
You are using imgRef but I can't see it defined anywhere. I can only see the state defined not the imgRef. If this is just the copy paste mistake from the original code then it's fine ignore this comment and if not please add const ref = useRef();
below the state.
Also you can change the if condition to something like !imgRef?.current?.contains(e.target)
this is more concise and easy to read and make the code look better.
Please first check that the state is changing when you click on the image from isOpen === true to isOpen === false because it is possible it is not change. To make the state change easy just use the following onClick={() => { setIsOpen(!isOpen); }}
this will help to change to opposite state when the image is clicked easily. According to what i can see the problem is maybe with the css class name className={"dropdownn1 " + (isOpen ? "open" : "closed")
and it may not be assigning names properly. As an alternate to this you can simply remove the line and pass the isOpen state as a prop to the <Dropdown />
menu and use something like this inside the component const Dropdown = ({ open }) => { return ( <div > {open && <div className="dropdown_container"></div>} </div>);}
from react.
None of them worked @ag533
IsOpen remains true even when I click on profile icon again and again.
from react.
Create a handleClick function to set state. Something like
Def handleClick = () => {
setIsOpen(!open)
}
An call this function in onClick rather than setting the state directly in onClick. As setting the state directly can lead error in the code - see this article - https://refine.dev/blog/common-usestate-mistakes-and-how-to-avoid/
from react.
Firstly boss, you did not reference the imgRef.
It should be const imageRef = React.useRef()
import React, {useState, useRef} from 'react'
const Navbar = () => {
const [isOpen, setIsOpen] = useState(false);
const imgRef = useRef()
useEffect(() => {
const closeDropdown = (e) => {
if (imgRef.current && !imgRef.current?.contains(e.target)) {
setIsOpen(false);
}
};
document.body.addEventListener("click", closeDropdown);
return () => document.body.removeEventListener("click", closeDropdown);
}, []);
return (
<div>
<div>
<div className={"dropdownn1 " + (isOpen ? "open" : "closed")}>
<Dropdown />
</div>
<div className="profile_icon_div" ref={imgRef}>
<img
src={profileImageUrl}
onClick={() => setIsOpen((prev) => !prev)}
className="profile_icon_image"
alt=""
/>
</div>
</div>
);
};
export default Navbar;
Also do confirm from you dev tools to see if the state of isOpen changes on click (i.e from false to true)
from react.
Updated the original code @umeh-promise ..check now..still not working
from react.
tried this too @ag533 .. still not working
from react.
Hey @RahulMittal18,
Try this solution it's working fine for me - https://codesandbox.io/s/quiet-sky-s85kqe?file=/src/App.js. It is similar to you solution but without the overhead complications of the CSS 😄. Let me know if this helps.
All the best 😸
from react.
@RahulMittal18 Please share all dependencies of this file, like the CSS code you used in this file and the Dropdown component's code.
from react.
@ag533 read the complete expected behaviour once again.
Dropdown is not closing on clicking outside the navbar
from react.
@rachit298 It is not possible to share here. At max, I can schedule a meet for this.
from react.
@RahulMittal18 You can create a repo and put all files in there. And share that repo link in original issue here.
from react.
@RahulMittal18 I have modified the sandbox respective to the expected behaviour - https://codesandbox.io/s/quiet-sky-s85kqe?file=/src/withClickOutside.js:0-574. Please have a look and let me know if this works for you. Basically what i have done is created a wrapper for the component that can be implemented for the whole page.
from react.
@ag533 it's working but i can't impplement it in my code
from react.
In that case please share bits of your code in a sandbox in a runnable state so that I can see it over there and help you @RahulMittal18 😊. As it is very difficult to replicate your exact behaviour in my system.
from react.
Can someone please create a sandbox for the original code? I see there are many solutions. I want to post the idiomatic one but I don't have any sandbox to modify because they're all doing something different.
from react.
Alright @RahulMittal18 can you please share the code sandbox for this so we can easily debug the code.
from react.
@umeh-promise @gaearon @ag533 @rachit298 sharing my code sandbox link.. Help me out guys
https://codesandbox.io/s/festive-oskar-gyry34?file=/src/App.js
from react.
@RahulMittal18
To fix the issue, I added the stopPropagation() method to the child element's event handler function handleProfileClick() to prevent the event from propagating up to the parent elements. This ensured that the parent event handler function closeDropdown(), which was closing the dropdown menu, was not triggered when the user clicked inside the menu. I also changed document.body.addEventListener() to document.addEventListener() in the closeDropdown() function to close the dropdown menu when the user clicks anywhere in the document, not just in the NavbarNew component.
I also updated the setIsOpen() method inside the handleProfileClick() function to toggle the isOpen state based on its previous value using the prevState function argument. This ensures that the isOpen state is updated correctly, even if multiple updates are triggered in quick succession.
With these changes, the dropdown menu now stays open when the user clicks inside the menu or anywhere in the document, but still closes when the user clicks outside the menu.
All changes were made in the NavbarNew component.
(https://codesandbox.io/s/amazing-khorana-2pqz7d?file=/src/components/NavbarNew.js)
from react.
@umeh-promise document.addEventListener is not working on my localhost. even the dropdown does not get open..
after using document.body.addEventListener it is working as before not like yours in code sandbox
from react.
@umeh-promise I changed "click" with "mouseup"...now its working as before with document.addEventListener but not working as expected.
Changes I did:
const handleProfileClick = (e) => {
e.stopPropagation();
// I ammended this line of code from setIsOpen(!isOpen) to setIsOpen((prevState) => !prevState);
// setIsOpen((prevState) => !prevState) toggles the state from true to false
setIsOpen((prevState) => !prevState);
};
useEffect(() => {
const closeDropdown = (e) => {
// console.log(
// e.target,
// imgRef.current,
// isOpen,
// e.path,
// imgRef.current.contains(e.target)
// );
if (imgRef.current && !imgRef.current?.contains(e.target)) {
setIsOpen(false);
// console.log("entered");
}
};
document.addEventListener("mouseup", closeDropdown);
return () => document.removeEventListener("mouseup", closeDropdown);
}, [isOpen]);
from react.
This actually might be from your local machine
Did you try it using the link I attached here.
Test it out it's working.
https://codesandbox.io/s/amazing-khorana-2pqz7d?file=/src/components/NavbarNew.js
from react.
@umeh-promise code in your link is working which has react-version 18 and i had react 16..upgrading it to 18 is causing many dependency conflicts. so i am not able to upgrade it to 18
from react.
@umeh-promise give a solution for react version 16.13.1
from react.
Adding if statement for isOpen
can solve the problem
const Navbar = () => {
const [isOpen, setIsOpen] = useState(false);
const imgRef = useRef();
useEffect(() => {
let closeDropdown = (e) => {
if (imgRef.current && !imgRef.current.contains(e.target)) {
setIsOpen(false);
}
};
document.body.addEventListener("click", closeDropdown);
return () => document.body.removeEventListener("click", closeDropdown);
}, []);
const toggleDropdown = () => {
setIsOpen((prev) => !prev);
};
return (
<div>
<div className={"dropdownn1 " + (isOpen ? "open" : "closed")}>
<Dropdown />
</div>
<div className="profile_icon_div" ref={imgRef}>
<img
src={profileImageUrl}
onClick={toggleDropdown}
className="profile_icon_image"
alt=""
/>
</div>
</div>
);
};
export default Navbar;
from react.
I would like to work on this issue, can you please assign it to me?
from react.
@RahulMittal18 instead of using a document.body use window.addEventListener that should solve your issue
can you please add a border to this both div tags and check are you clicking outside the div
you can use this has your reference
https://codesandbox.io/s/frosty-grass-sx0zty?file=/src/App.tsx
from react.
const Navbar = () => {
const [isOpen, setIsOpen] = useState(false);
const imgRef = useRef();
useEffect(() => {
let closeDropdown = (e) => {
if (imgRef.current && !imgRef.current.contains(e.target)) {
setIsOpen(false);
}
};
document.body.addEventListener("click", closeDropdown);
return () => document.body.removeEventListener("click", closeDropdown);
}, []);
const handleProfileIconClick = () => {
setIsOpen((prev) => !prev); // Toggle the dropdown
};
return (
<div className={"dropdownn1 " + (isOpen ? "open" : "closed")}>
<img
src={profileImageUrl}
onClick={handleProfileIconClick} // Update the event handler
className="profile_icon_image"
alt=""
/>
);
};
export default Navbar;
it will definitely work try this
from react.
@RahulMittal18 The only way I could be of help to you is if you do add me to the project repo.
That way I can have access to the React 16 version you are using and do the debugging or better still, send me the project link.
Thank you.
from react.
You can try adding a if condition to check if you are clicking the profile icon. If yes then toggle isOpen
Note that you are not mentioning anything about what will happen if we click on the profile image (imgRef).
Here is my code:
const Navbar = () => {
const [isOpen, setIsOpen] = useState(false);
const imgRef = useRef();
useEffect(() => {
let closeDropdown = (e) => {
if (imgRef.current && !imgRef.current.contains(e.target)) {
setIsOpen(false);
}
//Here's what I added
if(imgRef.current.contains(e.target)){
setIsOpen((prev) => !prev);
}
};
document.body.addEventListener("click", closeDropdown);
return () => document.body.removeEventListener("click", closeDropdown);
}, []);
return (
<div>
<div className={"dropdownn1 " + (isOpen ? "open" : "closed")}>
<Dropdown />
</div>
<div className="profile_icon_div" ref={imgRef}>
<img
src={profileImageUrl}
onClick={() => setIsOpen((prev) => !prev)}
className="profile_icon_image"
alt=""
/>
</div>
</div>
);
};
export default Navbar;
from react.
Perfect guys
from react.
why don't you add conditional rendering for onClick method. just correct me if i'm wrong guys.
from react.
Related Issues (20)
- Google Translate causing "Text content does not match server-rendered HTML" HOT 1
- Bug: useFormState formAction becomes null in strict mode HOT 1
- Bug: Source is not showing in 5.0.2 HOT 8
- Question and suggest: The official identifier of Server Compnoent and Client Component HOT 3
- Bug: when installing the application, the old version of "react-scripts" is installed HOT 1
- Bug: Uncaught DOMException: Failed to set the 'value' property on 'HTMLInputElement': This input element accepts a filename, which may only be programmatically set to the empty string. HOT 4
- Bug: optimistic state (useOptimistic) shows both optimistic and returned from server data when running several async actions HOT 6
- [DevTools Bug]: React Profiler reports higher hook numbers than shown in Components HOT 2
- about the react performance (how to improve it) HOT 3
- Bug: use() hook HOT 4
- Bug: Flight (RSC) examples are not accessible HOT 1
- useMemo reruns when the dependencies not changed when memoised value is a fn HOT 3
- Bug: [Flight] Async server components in `ai/rsc` not rendered correctly HOT 1
- Bug: React Dev tools extension showing wrong source file path on inspection HOT 4
- Bug: Using the hook useDeferredValue - Suspense fallback didn't show the contents HOT 4
- Bug: react-intl formatMessage cannot format message with param that neat by Single quotation mark HOT 3
- custom use directives + using closure serializer
- In react fiber, is didReceiveUpdate related to dirty checking?
- Naming convention HOT 1
- Bug: Rapid click fails to catch the onClick event properly
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from react.