I am currently building an app in React and I simply can't understand why this event is not working.
I tried other events and they work fine. I thought maybe I am trying to scroll the wrong DOM element but the other events work on it.
This is my code:
export default function App() {
const [scroll, setScroll] = useState("visible");
const handleScroll = () =>{
console.log("Scroll")
}
const handleClick = () =>{
console.log("HandleClick")
}
return (
<div onScroll={handleScroll} className="container">
<Navbar />
<PageContent />
<Footer/>
</div>
)
}
Related
I have a modal that I want to appear on a button click. This works fine, however, in order for it to be positioned correctly, I need to move the modal component to be rendered in a parent component.
I'm unsure how to do this as I'm not sure how I would pass the state down to the component where the button click is created. I'm also unsure of whether this is about passing a state or using a button onClick outside the component the state is defined in.
My code works and does what I want, but, I need <DeleteWarehouseModal show={show} /> to be in the parent component below. How can I do this?
The parent component where I want to render my modal:
function WarehouseComponent(props) {
return (
<section>
<div>
<WarehouseListItems warehouseData={props.warehouseData} />
//Modal component should go here
</div>
</section>
);
}
The component (WarehouseListItems) where the modal is currently being rendered:
function WarehouseListItem(props) {
const [show, setShow] = useState(false);
return (
<>
//some code necessary to the project, but, irrelevant to this issue
<Link>
<div onClick={() => setShow(true)}></div>
</Link>
<DeleteWarehouseModal show={show} />
</>
);
}
The modal:
const DeleteWarehouseModal = (props) => {
if (!props.show) {
return null;
}
return (
//some elements here
);
};
Yes, you can move the state and it's handler in WarehouseComponent component and pass the handler down to child component, which can change the state in parent component.
WarehouseComponent :-
function WarehouseComponent(props) {
const [show, setShow] = useState(false);
const toggleShow = () => {
setShow(state => !state);
}
return (
<section>
<div>
<WarehouseListItems
warehouseData={props.warehouseData}
toggleShow={toggleShow}
/>
<DeleteWarehouseModal show={show} />
</div>
</section>
);
}
WarehouseListItems : -
function WarehouseListItem(props) {
const {toggleShow} = props;
return (
<>
//some code necessary to the project, but, irrelevant to this issue
<Link>
<div onClick={() => toggleShow()}></div>
</Link>
</>
);
}
I cannot for the life of me figure out why this isn't working. I have a WorkoutCard component:
WorkoutCard:
const key = require('weak-key');
function WorkoutCard({ workout }) {
const { userID } = useContext(AuthContext);
const [modalOpen, setModalOpen] = useState(false);
const closeModalCallback = () => setModalOpen(false);
return (
<div className="WorkoutCard" onClick={() => setModalOpen(true)}>
<div className="header">
<h2>{workout.name}</h2>
<h3>Days</h3>
{workout.days.map((day) => {
return (
<p key={key({})}>{day}</p>
)
})}
<button className="deleteButton" onClick={handleDelete}>Delete</button>
</div>
<div className="line"></div>
<div className="exercises">
<h3>Exercises</h3>
{workout.exercises.map((exercise) => {
return (
<p key={key({})}>{exercise}</p>
)
})}
</div>
<EditWorkoutModal key={key({})} modalOpen={modalOpen} closeModalCallback={closeModalCallback} />
</div>
);
}
export default WorkoutCard;
And I have the EditWorkoutModal component:
Modal.setAppElement('#root');
function EditWorkoutModal({ modalOpen, workout, closeModalCallback }) {
const { userID } = useContext(AuthContext);
return (
<Modal isOpen={modalOpen} className="editModal">
<div className="rightHalf">
<p className='closeButton' onClick={() => closeModalCallback()}>+</p>
</div>
</Modal>
)
}
export default EditWorkoutModal
The problem here is that closeModalCallback is not changing the state whatsoever. It is called, but modalOpen is still set to true.
And, this is even more confusing, because I have this functionality working in another part of the app. I have a workouts page that has both WorkoutCard components, as well as a Modal, and it works this way. However, the closeModalCallback on the WorkoutCard components' modals will not work.
onClick events bubble up the DOM. For example, see the below snippet (see browser console for output):
const App = () => {
const parent = () => console.log("parent");
const child = () => console.log("child");
return <div onClick={parent}>
<div onClick={child}>Click me</div>
</div>
}
ReactDOM.createRoot(document.body).render(<App />);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.0.0/umd/react-dom.production.min.js"></script>
The above logs the following in the console:
> child
> parent
When you click on your child element, the click event bubbles up the DOM, eventually reaching your div with the WorkoutCard class, which fires the onClick that sets your modal-open state to true. You can stop the event from bubbling by calling e.stopPropagation() on your close-modal button:
onClick={(e) => {
e.stopPropagation();
closeModalCallback();
}}
This way the event won't bubble up to your parent div and trigger the onClick which is changing your state.
So here I have an App component where I have rendered the Navbar. I have a toggle function and logic on outside Click using useRef/useEffect. My intentions are when I click on the div where Navbar is located, I want to copy that div/img to specific part of the page using Css, and when it's moved I want in that copy text/h4 to be removed/dissapear. I would appriciate any help. Thanks
function App() {
const [isNavbarOpen, setIsNavbarOpen] = useState(false)
const navbar = useRef()
const openNavbar=()=>{
setIsNavbarOpen(true)
}
const closeNavbar=()=>{
setIsNavbarOpen(false)
}
const handleNavbar=(e)=>{
if(navbar.current && !navbar.current.contains(e.target)){
closeNavbar()
}
}
useEffect(()=>{
document.addEventListener('click', handleNavbar)
return() =>{
document.removeEventListener('click', handleNavbar)
}
},[])
return (
<>
<div className='smallProjects__container'
onClick={() => setIsNavbarOpen(!isNavbarOpen)} ref={navbar}>
<img
src="./images/icons/folr.png"/>
<h4>Navbar</h4>
{isNavbar? <Navbar closeNavbar={closeNavbar} />: null}
</div>
</>
);
}
export default App;
I'm new to React. I'm converting a vanilla JS app to a React app. When my vanilla app calls .focus() on the nav.timeline_context_menu element, the menu appears (due to some z-index manipulation). While converting to React, I'm having trouble figuring out how to target nav.timeline_context_menu element from the component that is supposed to trigger the .focus().
Desired outcome: if you right-click on a TimelineEvent component, it is supposed to trigger .focus() on the ContextMenu component.
This is what I have built so far. I've considered using context, but I can't wrap my brain around how. I'd appreciate your help.
Here is are the components:
/App.js
export default function App() {
return (
<BrowserRouter>
<Timeline />
<ContextMenu />
</BrowserRouter>
);
}
/components/Timeline.js
export default function Timeline(props){
const [timelineEvents, setTimelineEvents] = useState([])
useEffect(() => {
async function fetchData(){
/* gets an array of TimelineEvent components */
setTimelineEvents(await GetTimelineEvents())
}
fetchData()
}, [])
return (
<section className="timeline">
<ul>{timelineEvents}</ul>
</section>
)
}
/components/TimelineEvent.js
export default function TimelineEvent(props){
const [isFocused, setIsFocused] = useState(false)
return (
<li data-id={props.event.id} onContextMenu={
e => {
setIsFocused(true);
e.preventDefault();
}
}>
<div className="wrapper">
<div className="content">
<time>{props.event.injectTime}</time>
<span>{props.event.text}</span>
</div>
<div className="arrow"></div>
<div className="balloon" draggable="true"></div>
</div>
</li>
);
}
/components/ContextMenu.js
export default function ContextMenu(){
return (
<nav className="timeline_context_menu" tabIndex="0">
<h1>Options</h1>
<button className="btnEdit">Edit</button>
<button className="btnNew">New Injection</button>
<hr/>
<button className="btnDelete">Delete</button>
</nav>
);
}
i think when trying to do focus, the best to do here is create a ref to gain access to the dom node and use vanilla js to trigger focus
according to the docs https://reactjs.org/docs/accessibility.html#focus-control
I wanted to hide menu slider onclicking a body in reactjs. how can i do that in function using react.js.
document.querySelector('.open-menu').onclick = function(){
html.classList.add('active');
};
document.querySelector('.close-menu').onclick = function(){
html.classList.remove('active');
};
html.onclick = function(event){
if (event.target === html){
html.classList.remove('active');
}
};
I want this same functionality in react js.
Check the code below.
import React, { useState } from 'react';
const SomeComponent = () => {
const [isMenuOpen, showMenu] = useState(false)
const toggleMenu = () => showMenu(!isMenuOpen)
return (
<>
{isMenuOpen && <MenuCompoment />}
<div onClick={toggleMenu}><App /></div>
</>
)
}
This is a stripped down version of code I've used before.
UseEffect on mounting of the Menu adds an event listener on the document for the click event.
When a click happens it uses closest to look up the parent tree of elements for an id (note the '#')
If it finds one, then the click happened on the menu otherwise it happened on any other element so close.
When the menu is disposed the return function of useEffect is called and removes the event handler.
import React, {useState, useEffect} from 'react';
const Page = () => {
const [toggle, setToggle] = useState(false);
return <div>
<button type="button" onClick={e => setToggle(!toggle)}>Toggle</button>
{ toggle && <Menu show={toggle} hide={() => setToggle(false)}/>}
</div>
}
const Menu = ({show, hide}) => {
useEffect(() => {
document.addEventListener("click", listen);
return () => {
document.removeEventListener("click", listen);
}
}, []);
const listen = e => {
if (!e.target.closest("#menu")) {
hide();
}
}
return <div className="menu" id="menu">
<span>I'm a menu</span>
</div>;
}
i think setting onclick event on the menuItems like this will Work
onClick={()=> setOpen(!open)}
export function SidebarMenu({open, setOpen}) {
return (
<div open={open}>
<Link to="#" title="Home" onClick={()=> setOpen(!open)} >Home</Link>
</div>
)
}
Probably too late for answer but since I saw it in active feed, I will try my best to answer it.
I can see that if your menu is open, you want to hide it if clicked anywhere else. I have used useRef to store the menu node and I compare it to the document whenever its open, if it is, I close the menu
Codesandbox link