Two onPointerOver events conflict in React - javascript

My screen is divided in two zones: left zone and right zone.
The left zone appears always. When you point over the left zone, it should make appear the right zone.
Once the right zone is displayed, both zones should make the right zone display.
But its not working as expected, the right zone disappear when "trying" to point over it.
Check the demo HERE
export default function App() {
const [pointOverLeftZone, setPointOverLeftZone] = useState(false);
const [pointOverRightZone, setPointOverRightZone] = useState(false);
const shouldDisplayRightZone = pointOverLeftZone || pointOverRightZone;
return (
<div className="App">
<div
className="zone light-cyan"
onPointerOver={() => {
if (!pointOverLeftZone) setPointOverLeftZone(true);
}}
onPointerOut={() => {
if (pointOverLeftZone) setPointOverLeftZone(false);
}}
>
<p>Point over here to display the right zone</p>
</div>
{shouldDisplayRightZone && (
<div
className="zone light-yellow"
onPointerOver={() => {
if (!pointOverRightZone) setPointOverRightZone(true);
}}
onPointerOut={() => {
if (pointOverRightZone) setPointOverRightZone(false);
}}
>
<p>
Once open the right zone, both zones should activate the display of
this right zone, but the bug is here: when you mouse the move here
it dissapear
</p>
</div>
)}
</div>
);
}

Value of shouldDisplayRightZone depends on value of pointOverLeftZone, pointOverRightZone so you should make it an independent state and wrap into an useEffect and update whenever there are changes in pointOverLeftZone, pointOverRightZone
const [shouldDisplayRightZone, setShouldDisplayRightZone] = useState(
pointOverLeftZone || pointOverRightZone
);
useEffect(() => {
setShouldDisplayRightZone(pointOverLeftZone || pointOverRightZone);
}, [pointOverLeftZone, pointOverRightZone]);
Forked codesandbox

import React, { useState } from "react";
import "./styles.css";
export default function App() {
const [pointOverLeftZone, setPointOverLeftZone] = useState(false);
const [pointOverRightZone] = useState(false);
const shouldDisplayRightZone = pointOverLeftZone || pointOverRightZone;
return (
<div className="App">
<div
className="zone light-cyan"
onPointerOver={() => setPointOverLeftZone(true)}
>
<p>Point over here to display the right zone</p>
</div>
{shouldDisplayRightZone && (
<div
className="zone light-yellow"
onPointerOut={() => setPointOverLeftZone(false)}
>
<p>
Once open the right zone, both zones should activate the display of
this right zone, but the bug is here: when you mouse the move here
it dissapear
</p>
</div>
)}
</div>
);
}
Something like this?

import React, { useState } from "react";
import "./styles.css";
export default function App() {
const [pointOverLeftZone, setPointOverLeftZone] = useState(false);
const [pointOverRightZone, setPointOverRightZone] = useState(false);
const [flag, setFlag] = useState(true);
const [int, setIni] = useState(false);
const shouldDisplayRightZone = pointOverLeftZone || pointOverRightZone;
return (
<div className="App">
{flag === true ? (
<div
className="zone light-cyan"
onPointerOver={() => {
if (!pointOverLeftZone) {
setPointOverLeftZone(true);
}
}}
>
<p>Point over here to display the right zone</p>
</div>
) : (
<div>
<div>right zone open</div>
<p>
Once open the right zone, both zones should activate the display of
this right zone, but the bug is here: when you mouse the move here
it dissapear
</p>
</div>
)}
{shouldDisplayRightZone && (
<div
className="zone light-yellow"
onPointerOver={() => {
if (!pointOverRightZone) {
setFlag(false);
setPointOverRightZone(true);
}
}}
onPointerOut={() => {
if (pointOverRightZone) setPointOverRightZone(false);
}}
>
<p>
Once open the right zone, both zones should activate the display of
this right zone, but the bug is here: when you mouse the move here
it dissapear
</p>
</div>
)}
</div>
);
}
i have changed the code in sandbox you can check it there.Let me know if it works

Related

Change styles on hover of an appropriate item

How can I Change styles on hover of an appropriate item react? Now the styles are changed of all of the items at a time. Hovering on add to cart button I need to change only the chosen div styles.
https://codesandbox.io/s/trusting-moon-djocul?file=/src/components/Category.js**
import React, { useState } from "react";
import styles from "./category.module.css";
import Categories from "./Categories";
const Category = () => {
const [hovered, setHovered] = useState(false);
const [data, setData] = useState(Categories);
const style = hovered
? { backgroundColor: "#ffcbcb", color: "#fff", transition: "all 0.5s ease" }
: {};
const filterResult = (catItem) => {
const result = Categories.filter((curData) => curData.category === catItem);
setData(result);
};
return (
<>
<div className={styles.items}>
{data.map((value) => {
const { id, title, price, description } = value;
return (
<>
<div className={styles.item} key={id} style={style}>
<h1>{title}</h1>
<p>
{price} <span>$</span>
</p>
<p>{description}</p>
<button
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
className={styles.btn}
>
Add to Cart
</button>
</div>
</>
);
};
export default Category;
That's because you have a single "hovered" state shared between all your cards, you should create a "Card" component and have that component have its own hovered state
return (
<>
<div className={styles.items}>
{data.map((value) => {
return (
<>
<Card {...props} />
</>
);
Problem
This issue is occurring cause you are applying CSS to all the cards. The only small thing you are missing in your logic is adding CSS to the only card whose button was being hovered.
Solution
That can be achieved by using event objects on mouse enter and mouse leave events.
<div className={styles.item} key={id} style={style}>
<h1>{title}</h1>
<p>
{price} <span>$</span>
</p>
<p>{description}</p>
<button
onMouseEnter={(e) =>
e.currentTarget.parentElement.classList.add("active_card")
}
onMouseLeave={(e) =>
e.currentTarget.parentElement.classList.remove("active_card")
}
className={styles.btn}
>
Add to Cart
</button>
</div>
This will add a class of "active_card" on the card whose Add To Card button is being hovered, then you can apply your desired styling to that class.
.active_card {
background-color: #ffcbcb !important;
}
Example
Working Code Sandbox Example

How to toggle class in react, but one component at once(all with the same classes)

let me explain my situation.
I am building a MERN project to my portfolio and I am trying to make a button toggle between the name of an item and a inputfield. So when the user click the pen (edit), it will add a class with the displain:none; in the div with the text coming from the MongoDB data base to hide it and will remove it from the div with the input. I could manage to do it. BUT since the amount of items can inscrease, clicking in one of them cause the toggle in all of them.
It was ok until I send some useState as props to the component.
This is my code from the App.jsx
import React, {useState, useEffect} from "react";
import Axios from "axios";
import "./App.css";
import ListItem from "./components/ListItem";
function App() {
//here are the use states
const [foodName, setFoodName] = useState("");
const [days, setDays] = useState(0);
const [newFoodName, setNewFoodName] = useState("");
const [foodList, setFoodList] = useState([]);
//here is just the compunication with the DB of a form that I have above those components
useEffect(() => {
Axios.get("http://localhost:3001/read").then((response) => {
setFoodList(response.data);
});
}, []);
const addToList = () => {
Axios.post("http://localhost:3001/insert", {
foodName: foodName,
days: days,
});
};
const updateFood = (id) => {
Axios.put("http://localhost:3001/update", {
id: id,
newFoodName: newFoodName,
});
};
return (
<div className="App">
//Here it starts the app with the form and everything
<h1>CRUD app with MERN</h1>
<div className="container">
<h3 className="container__title">Favorite Food Database</h3>
<label>Food name:</label>
<input
type="text"
onChange={(event) => {
setFoodName(event.target.value);
}}
/>
<label>Days since you ate it:</label>
<input
type="number"
onChange={(event) => {
setDays(event.target.value);
}}
/>
<button onClick={addToList}>Add to list</button>
</div>
//Here the form finishes and now it starts the components I showed in the images.
<div className="listContainer">
<hr />
<h3 className="listContainer__title">Food List</h3>
{foodList.map((val, key) => {
return (
//This is the component and its props
<ListItem
val={val}
key={key}
functionUpdateFood={updateFood(val._id)}
newFoodName={newFoodName}
setNewFoodName={setNewFoodName}
/>
);
})}
</div>
</div>
);
}
export default App;
Now the component code:
import React from "react";
//Material UI Icon imports
import CancelIcon from "#mui/icons-material/Cancel";
import EditIcon from "#mui/icons-material/Edit";
//import CheckIcon from "#mui/icons-material/Check";
import CheckCircleIcon from "#mui/icons-material/CheckCircle";
//App starts here, I destructured the props
function ListItem({val, key, functionUpdateFood, newFoodName, setNewFoodName}) {
//const [foodList, setFoodList] = useState([]);
//Here I have the handleToggle function that will be used ahead.
const handleToggle = () => {
setNewFoodName(!newFoodName);
};
return (
<div
className="foodList__item"
key={key}>
<div className="foodList__item-group">
<h3
//As you can see, I toggle the classes with this conditional statement
//I use the same classes for all items I want to toggle with one click
//Here it will toggle the Food Name
className={
newFoodName
? "foodList__item-newName-delete"
: "foodList__name"
}>
{val.foodName}
</h3>
<div
className={
newFoodName
? "foodList__item-newName-group"
: "foodList__item-newName-delete"
}>
//Here is the input that will replace the FoodName
<input
type="text"
placeholder="The new food name..."
className="foodList__item-newName"
onChange={(event) => {
setNewFoodName(event.target.value);
}}
/>
//Here it will confirm the update and toggle back
//Didn't implement this yet
<div className="foodList__icons-confirm-group">
<CheckCircleIcon
className="foodList__icons-confirm"
onClick={functionUpdateFood}
/>
<small>Update?</small>
</div>
</div>
</div>
//here it will also desappear on the same toggle
<p
className={
newFoodName
? "foodList__item-newName-delete"
: "foodList__day"
}>
{val.daysSinceIAte} day(s) ago
</p>
<div
className={
newFoodName
? "foodList__item-newName-delete"
: "foodList__icons"
}>
//Here it will update, and it's the button that toggles
<EditIcon
className="foodList__icons-edit"
onClick={handleToggle}
/>
<CancelIcon className="foodList__icons-delete" />
</div>
</div>
);
}
export default ListItem;
I saw a solution that used different id's for each component. But this is dynamic, so if I have 1000 items on the data base, it would display all of them, so I can't add all this id's.
I am sorry for the very long explanation. It seems simple, but since I am starting, I spent the day on it + searched and tested several ways.
:|

React not rendering jsx in onClick Button

I am new to learning react and am stuck with this doubt. I have a simple button and on click of that button I want to add some text (or any other html) element. The console log statement is getting executed but the div tag is not getting rednered. This is my following code.
function App() {
const executeMe = () => {
console.log("executed")
return(
<div> Clicked here</div>
)
}
return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<div className="App">
Hello world
<Button onClick={executeMe}> click me</Button>
</div>
</LocalizationProvider>
);
}
export default App;
I know that I am missing out something which may be very simple. Please help me fix this. Thanks
Your looking at React wrongly, it doesn't work this way. You can do this instead.
import { useState } from "react";
function App() {
const [clicked, setClicked] = useState(false);
const [lines, setLines] = useState([]);
const executeMe = () => setClicked(!clicked);
const onAddLine= () => setLines(lines.concat("New line (Could be unique)"));
return (
<div className="App">
Hello world
{/* METHOD A */}
{!clicked && <button onClick={executeMe }>Click me</button>}
{clicked && <div>Clicked here</div>}
<br />
{/* METHOD B */}
<button onClick={executeMe}>{clicked ? "Clicked here" : "Click me"}</button>
<br />
{/* ADDITIONAL FUN STUFF WITH SEPERATE BUTTON */}
<button onClick={onAddLine}>Add new line</button>
<br />
{lines.map((line, x) => {
return(
<div key = {x}>{x+1} : {line}</div>
);
})}
</div>
);
};
export default App;
You can render that div by using state instead and reset it on the next click.
function App() {
const [showDiv, setShowDiv] = useState(false);
const executeMe = () => {
console.log("executed");
setShowDiv(!showDiv);
};
return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<div className="App">
Hello world
<Button onClick={executeMe}> click me</Button>
{showDiv && <div> Clicked here</div>} {/* render div once showDiv state is true */}
</div>
</LocalizationProvider>
);
}
export default App;
You should add a state value to check when the button has been pressed.
Here is more information about how to use useState hook.
function App() {
const [isButtonPressed, setIsButtonPressed] = useState(false);
const executeMe = () => {
console.log("executed");
setIsButtonPressed(true);
}
return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<div className="App">
Hello world
<Button onClick={executeMe}> click me</Button>
{isButtonPressed && <div>Clicked here</div>}
</div>
</LocalizationProvider>
);
}
export default App;
There are many ways to achieve it.
First React is just JavaScript, most JS code will work within the component.
But some dev might find it not so React which is weird for me :)
So here are the two examples that you might try:
function App() {
const [list, setList] = React.useState([])
const handleAddLine = () => {
const lists = document.getElementById('lists')
const li = document.createElement('li')
li.textContent = 'hey'
lists.append(li)
}
const handleAddLineReactish = () => {
setList(prevList => {
return prevList.concat(<li>hey</li>)
})
}
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<button onClick={handleAddLine}>Add</button>
<ul id='lists'></ul>
<button onClick={handleAddLineReactish}>Add Reactish</button>
<ul>
{list.length > 0 && list.map((l, i) => {
return (
<li key={i}>{l}</li>
)
})}
</ul>
</div>
);
}
sandbox URL: https://codesandbox.io/s/funny-sun-7f4epn?file=/src/App.js
For something like this we use a react hook called "useState".
In "useState" we store a something and on the basis of that we do stuff like to show, hide and more.
See the image
you can write that html code in another component and import it into the current file you can make useState to check the value is 'visible' with type 'true/false' to check the state when the button is click.
code example
import React, { useState } from "react";
function App() {
const [showText, setShowText] = useState(false);
const executeMe = () => {
console.log("executed")
setShowText(true);
}
return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<div className="App">
Hello world
<Button onClick={executeMe}> click me</Button>
{showText ? <Text /> : null}
</div>
</LocalizationProvider>
);
}
const Text = () => <div>You clicked the button!</div>;
export default App;

React and Sanity - Button is targeting wrong data

I am building my website portfolio using React and Sanity. This actually is my first project with React. The idea was to use sanity in order to store data that I can use on my website, such as "projects" and so far everything is going well, except for one thing: THE BUTTON IS TARGETING WRONG DATA.
The projects are divided in categories: UX/UI - React - JavaScript - University Projects - All
Everything is working fine, the tags imported from sanity's schemas allow me to categorise the projects.
Every project looks like a little card and when hovered, there is a little description as long as the button "MORE+".
HERE IS THE PROBLEM
When I click the button, there is a big window showing up where I can see what is the project about.
Right now there are two projects on sanity (let's call them A and B).
Project A is categorised as JavaScript and project B as React and UI/UX.
If I hover on project A and Click the button "MORE+", it would open project B on the big window, why is that?
This happens only when I am in the category "ALL" but I assume it doesn't happen in other categories only because there is only one project each category, while in "ALL" both projects are shown.
I leave below the code that I used for the button and how I imported this from sanity.
It may look a bit confusing and long, only because I used a lot of motion frame and wrapped everything in a lot of div
Also in few point it is still uncomplete.
import React, { useState, useEffect } from 'react';
import {AiFillEye, AiFillGithub} from 'react-icons/ai';
import {motion} from 'framer-motion';
import './Work.scss';
import { HiX } from 'react-icons/hi';
import { AppWrap } from '../../wrapper';
import {urlFor, client} from '../../client';
const Work = () => {
const [works, setWorks] = useState([]);
const [filterWork, setFilterWork] = useState([]);
const [activeFilter, setActiveFilter] = useState('All');
const [animateCard, setAnimateCard] = useState({ y: 0, opacity: 1 });
const [toggle, setToggle] = useState(false);
useEffect(() => {
const query = '*[_type == "works"]';
client.fetch(query).then((data) => {
setWorks(data);
setFilterWork(data);
});
}, []);
const handleWorkFilter = (item) => {
setActiveFilter(item);
setAnimateCard([{ y: 100, opacity: 0 }]);
setTimeout(() => {
setAnimateCard([{ y: 0, opacity: 1 }]);
if (item === 'All') {
setFilterWork(works);
} else {
setFilterWork(works.filter((work) => work.tags.includes(item)));
}
}, 500);
};
return (
<>
<h2 className="portfolio-head-text">My <span>Portfolio</span></h2>
<div className="app__work-filter">
{['UI/UX','JavaScript', 'React JS', 'University Projects', 'All'].map((item, index) => (
<div key={index}
onClick={() => handleWorkFilter(item)}
className={`app__work-filter-item app_flex p-text ${activeFilter === item ? 'item-active' : ''}`}>
{item}
</div>
))}
</div>
<motion.div
animate={animateCard}
transition={{duration:0.5, delayChildren: 0.5}}
className="app__work-portfolio"
>
{filterWork.map((work,index) => (
<div className="app__work-card-container" key={index}>
<div className="app__work-item app__flex">
<div className="app__work-img app__flex">
<img src={urlFor(work.imgUrl1)} alt={work.name}/>
<motion.div
whileHover={{opacity:[0,1]}}
transition={{duration: 0.3, ease: 'easeInOut', staggerChildren: 0.6}}
className="app__work-hover app__flex">
<p>{work.descriptionPreview}</p>
<motion.div
whileInView={{scale:1}}
whileHover={{scale:[1,0.9]}}
transition={{duration: 0.2}}
className="app__flex"
>
<button onClick={() => setToggle(true)}>more+</button>
</motion.div>
</motion.div>
</div>
<div className="app__work-content app__flex">
<h4 className="bold-text">{work.title}</h4>
<p className="p-text" style={{marginTop: 10}}>{work.tagView}</p>
</div>
</div>
{toggle &&(
<div className="app__work-big-window">
<div className="window-img-x">
<img classname="window-img" src={urlFor(work.imgUrl1)} alt={work.name}/>
<div><HiX className="window-x" onClick={() => setToggle(false)}/></div>
</div>
<div>
<h4>{work.title}</h4>
<h6>{work.subTitle}</h6>
<div/>
<p>{work.description}</p>
</div>
<div/>
<div>
<h6>Technologies used: </h6>
<p>{work.tech}</p>
</div>
</div>
)}
</div>
))}
</motion.div>
</>
)
}

React, onMouseEnter event trigger all items instead of one hovered?

I have two cards now when I hover on one card it triggers in all two cards on hover (onMouseEnter)
Here is the solutions I have
import React, { useState } from "react";
const Buttons = () => {
const [isShown, setIsShown] = useState(false);
return (
<div>
<div
onMouseEnter={() => setIsShown(true)}
onMouseLeave={() => setIsShown(false)}
className="wrapper-btn"
>
{isShown && <button> test 1 </button>}
</div>
<div
onMouseEnter={() => setIsShown(true)}
onMouseLeave={() => setIsShown(false)}
className="wrapper-btn"
>
{isShown && <button> test 2 </button>}
</div>
</div>
);
};
export default Buttons;
What is wrong here?
both share the same state, you can abstract your code to another component where each one has an independent state:
import React, { useState } from "react";
const Buttons = () => {
return (
<div>
<ButtonDisplay btnContent='test 1' />
<ButtonDisplay btnContent='test 2' />
</div>
);
};
export default Buttons;
const ButtonDisplay = ({ btnContent }) => {
const [isShown, setIsShown] = useState(false);
return (
<div
onMouseEnter={() => setIsShown(true)}
onMouseLeave={() => setIsShown(false)}
className="wrapper-btn"
>
{isShown && <button> { btnContent } </button>}
</div>
)}
this would be the approach I would take since keeps your code dry.
other approach possible would change isShown state to an array that tracks each button isShown state, where onMouseEnter|Leave would update a specific index of that array and also read from that one, hence you would render your button based on specific value from an index of your state. or you could create a state to each button which would be the least optimal when you have multiple buttons.

Categories