Click Handler.
const handleClick = (event) => {
console.log(event.target);
}
Return.
{ menu.map((menuItem, index) => (
<div onClick={handleClick}>
<div>{menuItem.text}</div>
<img src={menuItem.image} /></div>
))
}
My console tells me that the event.target is the IMG element instead of the DIV. Why is this happening and how can I lock the event to the parent DIV? Do I just have to write logic to look at the IMG parent element?
Thanks y'all.
this is because Bubbling and capturing. event.target is the “target” element that initiated the event. it's the event that you clicked on it and in this case, it was an image. I think you can get div by event.currentTarget because the handler runs on it.
Not sure about your code, but forcing the scope to the one of the div should work as well:
const handleClick = (event) => {
console.log(event.target);
}
{
menu.map((menuItem, index) => (
<div onClick={evt => handleClick(evt)}>
<div>{menuItem.text}</div>
<img src={menuItem.image} /></div>
))
}
Which is basically what you had, but I edited <div onClick={evt => handleClick(evt)}>.
Related
I tried to trigger the click event of a button which was append into the body. but the click event got unwired when we appending an element in the React Functional components..please find the code below,
Code snippet:
const [value, setValue] = React.useState(0);
function increaseValue() {
console.log('click');
setValue(value + 1);
}
useEffect(() => {
var btnElement = document.getElementById('btn');
document.body.appendChild(btnElement);
}, []);
return (
<div className="control-pane">
<div className="control-section modal-dialog-target">
<div id="btn">
<button onClick={increaseValue}>Click</button>
<span>{value}</span>
</div>
</div>
</div>
);
If i remove the document.body.appendChild(btnElement); The click event works fine.
Sample: https://stackblitz.com/edit/react-ntrkyi-lefq4u?file=index.js,package.json,index.html
How can i fix this issue?
To be honest I'm not 100% sure what you're trying to do in the useEffect() but your button isn't working, can be updated to:
<button
type="button"
onClick={() => {
increaseValue();
}}
>
Click
</button>
That'll get the increment working.
I am trying to send the click event on an element but TypeScript does not like any and gives out a warning, so I am trying React.MouseEvent<HTMLElement> but then it throws an error.
`Property 'id' does not exist on type 'EventTarget'.`
const closeWindow = (e: React.MouseEvent<HTMLElement>) => {
if (e.target.id === 'modal-window') ...
}
return (
<div id='modal-window' onClick={closeWindow}>
<div id='modal-content'>...</div>
</div>
)
The problem is that e.target could be just about anything, because it's the innermost target of the event, not necessarily the element on which you set the event handler.
The element you hooked the event on is currentTarget, it works correctly:
const closeWindow = (e: React.MouseEvent<HTMLElement>) => {
if (e.currentTarget.id === 'modal-window') {
console.log("Match");
}
};
(Or you could use HTMLDivElement to be more specific.)
The reason is that if you clicked the span here:
<div onClick={handler}>
<span>Click me</span>
</div>
e.target would be the span, not the div. e.currentTarget is the div.
You've said you need to use e.target because you're using that to determine whether the click was on modal-window or modal-content. Although you could use a type assertion (they're both div elements), if you're differentiating between them anyway, perhaps have two handlers, one for each:
return (
<div id='modal-window' onClick={closeModalWindow}>
<div id='modal-content' onClick={closeModalContent}>...</div>
</div>
);
Then you wouldn't need the id values (unless you use them for something else) and the component would be reusable.
If you want clicks on modal-content to not trigger your handler, for instance:
return (
<div onClick={closeWindow}>
<div onClick={e => e.stopPropagation()}>...</div>
</div>
);
...then closeWindow doesn't need to use an if.
Context: I am trying to scroll view to props.toBeExpandItem item which keeps changing depending on click event in parent component. Every time a user clicks on some button in parent component I want to show them this list and scroll in the clicked item to view port. Also I am trying to avoid adding ref to all the list items.
I am using react ref and want to add it conditionally only once in my component. My code goes as below. In all cases the option.id === props.toBeExpandItem would be truthy only once in loop at any given point of time. I want to understand will it add any overhead if I am adding ref=null for rest of the loop elements?
export const MyComponent = (
props,
) => {
const rootRef = useRef(null);
useEffect(() => {
if (props.toBeExpandItem && rootRef.current) {
setTimeout(() => {
rootRef.current?.scrollIntoView({ behavior: 'smooth' });
});
}
}, [props.toBeExpandItem]);
return (
<>
{props.values.map((option) => (
<div
key={option.id}
ref={option.id === props.toBeExpandItem ? rootRef : null}
>
{option.id}
</div>
))}
</>
);
};
Depending upon your recent comment, you can get the target from your click handler event. Will this work according to your ui?
const handleClick = (e) => {
e.target.scrollIntoView()
}
return (
<ul>
<li onClick={handleClick}>Milk</li>
<li onclick={handleClick}>Cheese </li>
</ul>
)
Have a list of following items:
function UserItem (props) {
const [showPic, setMode] = useState(false);
return (
<div>
<div
onMouseEnter={() => setMode(true)}
onMouseLeave={() => setMode(false)}
>
{showPic && <div>PIC</div>}
{!showPic && <div>{props.login}</div>}
</div>
</div>
)
}
The problem is that when mouse moved fast onMouseLeave not fire on all items. I understand it has something to do with delegation. But cannot figure out what exactly. Both event should fire on exact element they are attached to.
Any ideas?
I'm not sure if it's a bug. But can you try like this?
{showPic == true ? <div>PIC</div> : <div>{props.login}</div>}
If this still does not work then you should file a bug.
I tried solutions provided on the internet but no luck. Here is the codepen link. This is how the code looks like:
//JSX:
<div className="drawer-component" onClick={this.closeDrawer}>
<div className="drawer-opener">
<button onClick={this.toggleDrawer}>Toggle</button>
</div>
{this.state.isOpen && <div class="drawer">Hello I am a drawer. Cliking on me should not close myself.</div>}
</div>
// Event Handlers:
toggleDrawer(e) {
e.stopPropagation();
this.setState((state, props) => {
return {isOpen: !state.isOpen};
})
}
closeDrawer(e) {
e.stopPropagation();
this.setState((state, props) => {
return {isOpen: false};
})
}
No idea what I am doing wrong, any help would be appreciated.
The behaviour matches the code written.
You have your text in a div(class='drawer') without any click handler, so the click handler of the parent (div class='drawer-component') gets executed, and in this case it is setting your state variable isOpen to false and closing your drawer. The e.stopPropagation() in this does not affect anything since that div does not have any further parent with a click handler to which the event might get propagated.
If what you intended was to have your text clickable without closing your drawer, add a click handler for the div (with class='drawer') which just prevents propagation.
closeDrawer(e) {
// e.stopPropagation(); This isn't required as there's nowhere further the event can get propagated
this.setState((state, props) => {
return {isOpen: false};
})
}
// Prevent click handler of parent being called and closing the drawer
preventClosingOnTextClick(e) {
e.stopPropagation();
}
render() {
return (
<div className="drawer-component" onClick={this.closeDrawer}>
<div className="drawer-opener">
<button onClick={this.toggleDrawer}>Toggle</button>
</div>
{
this.state.isOpen &&
<div class="drawer"
onClick={this.preventClosingOnTextClick}> // This prevents the closing
Hello I am a drawer. Cliking on me should not close myself.
</div>
}
</div>
);
}
};
);