take out name of dynamically created cards react - javascript

I had created some cards from an array of objects, now I want to show popup data for each card differently.
here is my code of printing
{data.carData.map( single=>(<li>{ <div onClick={handleClick}><Card single={single}/></div>} </li>))}
for this, I want the card name onClick event, but when I pass anything in the handleClick react throw an error of too many re-renders.
if I do the same onClick event inside the card component and log it prints all the cards names one by one
here is what is inside the card:
function Card({single}) {
const [flowName, setflowName] = useState();
const handleClick=(e)=>{
setflowName(e);
return
}
console.log("loging name:",flowName);
return (
<div className="main mb-2 z-0" onClick={handleClick(e=>single?.flowName)} >
<div className=" inner_main_container pt-4 px-8 bg-white shadow-lg rounded-lg ">
<div className="flex justify-between">
<div className="flex flex-row align-center">
</div>
{single?.badge.map(badge=>(
<div className={"badge"} key={badge}>
<span className={badge==="Growth"?" badgeClrG":(badge==="Content"?"content":"badgeClrO")} key={badge}>{badge}</span>
</div>
) )}
</div>
<div className="flex justify-center">
<img src={single?.image} alt={single?.flowName} />
</div>
<div >
<div className={"mt-2 flex justify-center"}>
<h1>{single?.flowName}</h1>
</div>
</div>
</div>
</div>
) } export default Card

I suspect you're doing this when you're trying to pass a value:
single=>(<li>{ <div onClick={handleClick(value)}><Card single={single}/></div>} </li>))}
Every time this is rendered, the function is invoked straight away, which causes another render and so on...
The solution is to wrap your handleClick call in another function:
single=>(<li>{ <div onClick={()=>handleClick(value)}><Card single={single}/></div>} </li>))}

Related

JS click event listener in laravel livewire component?

I'm trying to add some JS to add a click event to an element within a livewire component. The click event works as expected on first load, however as soon as I run a wire:click, the JS click events no longer work?
I can see that livewire is removing / updating the dom elements when I click the wire:click element so unsure whether this may have something to do with it.
What am I doing wrong? How should I be registering click events to livewire elements in JS and ensure they always work?
My javascript:
document.addEventListener('livewire:load', function () {
let pb_responsive_button = [...document.querySelectorAll('.js-pb-responsive')];
pb_responsive_button.map(function (btn) {
btn.addEventListener("click", function () {
console.log('click');
});
});
});
livewire:
<button wire:click="addComponentActive(true)">
<span class="font-bold text-sm">Add Page Block</span>
</button>
public function addComponentActive(bool $bool)
{
$this->add_component_active = $bool;
}
my view:
#if ($add_component_active === true)
<section class="bg-white shadow-lg rounded-sm mb-8 w-full h-[calc(100%-64px)] absolute z-50">
.....
</section>
#endif
<section class="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto">
<div class="border border-gray-200 rounded">
<div class="bg-gray-200 p-5 flex justify-between">
<div class="bg-white border border-gray-200 rounded p-2">
<span class="font-bold text-sm">Homepage</span>
</div>
<div class="bg-blue-600 text-white border border-gray-200 rounded p-2">
<button wire:click="addComponentActive(true)">
<span class="font-bold text-sm">Add Page Block</span>
</button>
</div>
<div class="flex justify-between items-center gap-2">
<div class="js-pb-responsive js-pb-mobile bg-white border border-gray-200 rounded p-2">M</div>
<div class="js-pb-responsive js-pb-tablet bg-white border border-gray-200 rounded p-2">T</div>
<div class="js-pb-responsive js-pb-desktop bg-white border border-gray-200 rounded p-2">D</div>
</div>
</div>
</div>
</section>
UPDATE:
I've updated it to show and hide the blocks rather than display it in a conditional if statement which ensures the click events still work, since the element still exists on page.
<section class="{{$add_component_active === true ? 'block' : 'hidden'}}"> ... </section>
Surely there is a better way to handle this. I notice I have a livewire:load eventListener? Is there another event I should be listening to when the livewire view is reloaded to reinitise the JS events?
Any help would be much appreciated.
Livewire works hand-in-hand with Alpine.js. You should focus on Alpine if you want strictly front-end functionality https://alpinejs.dev/directives/on
<button #click="alert('Hello World!')">Say Hi</button>

Issue with Changing state from 1 React Component inside of another React component

I've been trying to change the 'ModalOn' state which is created inside of the medCardSong.js file, and I've been trying to change that state from inside of the 'SongModal.js' file, which is a child component inside of medCardSong.js.
I've inputted the changeState function 'SetModalOn' as a prop to the SongModal.js component, and i've tried changing the state through that.
Here's medCardSong.js:
import React, { useEffect } from 'react';
import { useState} from 'react';
import SongModal from '../modals/SongModal';
function MediumCardSong(props) {
const [ModalOn, SetModalOn] = useState(false);
function killme() {
SetModalOn(false);
console.log(7)
}
console.log(ModalOn)
return (
<div className={" flex flex-col m-2 overflow-hidden duration-300 w-52 " + (ModalOn
? 'transition-none' : 'hover:scale-105 transition-all')} onClick={() =>
{SetModalOn(true);}}>
<img className='object-cover rounded-3xl'
src="https://i0.wp.com/coolhunting.com/wp-content/uploads/2022/07/steve-lacy-
bad-habit.jpg?fit=586%2C586&ssl=1" alt="" />
<div className='pb-2'>
<div className='flex'>
<div className='px-2 pt-2 text-2xl font-bold text-gray-400'>#1</div>
<div className='pl-3 text-xl pt-2 text-white'>Mercury</div>
</div>
<div className='text-left pl-5 text-gray-500'>Steve Lacy</div>
</div>
{ModalOn && <SongModal CloseModal={killme} />}
</div>
);
}
export default MediumCardSong;
and here's SongModal.js:
import React from 'react'
function SongModal(props) {
// setTimeout(() => {props.CloseModal(false)}, 1000)
return (
<div className="bg-neutral-800 bg-opacity-60 fixed inset-0 z-50 backdrop-blur-sm">
<div className="flex h-screen justify-center items-center">
<div className="justify-center bg-neutral-700 py-12 px-24 border-4 border-
pearmint rounded-xl text-xl text-white" >
<button className='text-3xl text-white pr-24 pb-24'
onClick={() => {props.CloseModal()}} >X</button>
sad
</div>
</div>
</div>
)
};
export default SongModal;
The imported CloseModal function works as intended when it's applied outside of the jsx. For example, the "SetTimeOut" piece of code would work properly if it's uncommmented. However this doesn't happen when I call "CloseModal" inside of an Onclick event-handler, such as the call I did for the 'x' Button.
I've also used console.log to see if the button has been registering the clicks I make and it has been. So I'm confused as to why the props.CloseModal function does not work as intended inside the OnClick event listener. Please give advice if you can.
try to call it inside of a hook
function SongModal(props) {
const close = () => {
props.CloseModal()
}
return (
<div>
<button onClick={close}>Close Btn</button>
</div>
)
};
also check the following acritical
link

How to distinguish user clicks between different buttons?

I have rendered 3 plan options from an object array I get from the backend.
If the plan being rendered is
cheaper, the user's subscription then its corresponding button would say downgrade,
costlier, the button would say upgrade, if it is the same then the button would say current.
This logic for rendering is working fine.
But when users click on a button I am not able to identify which option they clicked. I need to update the handle click events based on the plan being rendered.
Currently, I am iterating through the tiers map, and for each tier, I am rendering the button with appropriate text. The function to display the text basically checks for the tiered pricing and returns upgrade or downgrade or current plan. I need a way to update the handle click just like the text.
How can I dynamically update the handle click events based on the tier being rendered?
const [confirmation, setConfirmation] = useState(false);
const handleConfirmation = () => {
setConfirmation(true);
console.log('button is clicked');
};
<div className='px-8 lg:px-24 grid grid-cols-3 gap-8'>
{tiers.map((tier) => (
<div
key={tier.title}
className='relative p-8 bg-white border border-gray-200 rounded-2xl shadow-sm flex flex-col'
>
<div className='flex-1'>
<h3 className='text-xl font-semibold text-gray-900'>{tier.title}</h3>
{tier.value ? (
<p className='absolute top-0 py-1.5 px-4 bg-grays-600 rounded-full text-xs font-semibold uppercase tracking-wide text-white transform-translate-y-1/2'>
VALUE PLAN
</p>
) : tier.recommended ? (
<p className='absolute top-0 py-1.5 px-4 bg-blue-500 rounded-full text-xs font-semibold uppercase tracking-wide text-white transform -translate-y-1/2'>
RECOMMENDED PLAN
</p>
) : (
''
)}
<Button
text={determineCTAText(tier)}
size='fullwidth'
variant='primary'
className='m-auto mt-8 text-center block'
handleClick={handleConfirmation}>
</Button>
}
You can modify the handleConfirmation function to receive a tier object and return a function instead. This will create a closure over the tier value and let you access it when the button's callback is called.
const handleConfirmation = (tier) => {
// Returns the callback function that will be called, with the specific `tier` value in scope
return () => {
setConfirmation(true);
// You can access any `tier` property here
console.log(`button for tier ${tier.title} was clicked`);
};
}
return (
<div className='px-8 lg:px-24 grid grid-cols-3 gap-8'>
{tiers.map((tier) => (
{/* Omitted rest of the JSX for simplicity */}
<Button
text={determineCTAText(tier)}
size='fullwidth'
variant='primary'
className='m-auto mt-8 text-centerblock'
handleClick={handleConfirmation(tier)}>
</Button>
}
</div>
)

I'm trying to build a dropdown when cursor hovers on a navbar element pointing to that element with an arrow up

I am using NextJS and Tailwind CSS. I already built the dropdown but I have an issue building the arrow pointing to the specific element. I built the arrow in a previous version using a div rotated at 45deg but then I couldn't make my dropdown take the full screen. Now I have it full screen and I'm wondering how to make the arrow (div) point to the specific element I'm hovering on. I made sure to hide some details about the website because of confidentiality matters. Here's what I'm trying to achieve:
Here's the code I have so far:
import React from 'react'
import { navLinks } from '../data/navdata'
const DropdownHover = ({ index }) => {
return (
<div className="group-hover:block absolute left-0 w-full hidden text-dark-gray mt-8 bg-pink" aria-labelledby="dropdownButton">
<div className="justify-center">
<div className="flex py-10 px-20 text-sm justify-between">
{navLinks[index].hover.map((link, index) => {
return (
<div className="" key={index}>
<p className="text-navbar-gray py-2 uppercase font-semibold">{link.name}</p>
{link.links.map((sublink, index) => {
return(<p className="" key={index}><a className="bg-pink hover:text-red py-2 block whitespace-no-wrap" href={sublink.path}>{sublink.name}</a></p>)
})}
</div>
)
})}
</div>
<div className="flex text-sm px-20 py-10">
<div className='pr-40'>
<p className="text-navbar-gray py-2 uppercase font-semibold">Dummy Data</p>
<p className=""><a className="bg-pink hover:text-red py-2 block whitespace-no-wrap" href="#">Dummy Data</a></p>
<p className=""><a className="bg-pink hover:text-red py-2 block whitespace-no-wrap" href="#">Dummy Data</a></p>
<p className=""><a className="bg-pink hover:text-red py-2 block whitespace-no-wrap" href="#">Dummy Data</a></p>
</div>
<div>
<p className="text-navbar-gray py-2 uppercase font-semibold">Dummy Data</p>
<p className=""><a className="bg-pink hover:text-red py-2 block whitespace-no-wrap" href="#">Dummy Data</a></p>
<p className=""><a className="bg-pink hover:text-red py-2 block whitespace-no-wrap" href="#">Dummy Data</a></p>
<p className=""><a className="bg-pink hover:text-red py-2 block whitespace-no-wrap" href="#">Dummy Data</a></p>
</div>
</div>
</div>
</div>
)
}
export default DropdownHover
in CSS you can simply manipulate left property of the arrow if its positioned absolute:
li :nth-child(1):hover .arrow{
left:20rem;
}
li :nth-child(2):hover .arrow{
left:30rem;
}
but if you want to make it completely responsive, first get OffsetX of every li element then add an event listener on mouseclick.
for a better understanding you can check the following project on code pen.
https://codepen.io/piyushpd139/pen/gOYvZPG

How do I change inline CSS styles using a variable in JSX inside a map function?

Okay, so I have a map function that is running through an array and creating divs on the DOM for each item ("colorItem") in the array. The array is an array of colors, each item in the array is the hex value of a color (example: #1a703f).
I'm trying to change the background of each div item so it matches the item from the array. However because I cant get access the variable inside the map function inside the inline CSS JSX.
{this.state.colorsArray.map(colorItem =>
<div className="m-4">
<div className="max-w-sm rounded overflow-hidden shadow-lg w-48">
<div style={{ backgroundColor: {colorItem} }} className="h-32">
</div>
<div className="px-6 py-4">
<p className="text-grey-darker">
{colorItem}
</p>
</div>
</div>
</div>
`
Something like this might work for you:
{this.state.colorsArray.map(colorItem => {
let colorstyle = {
backgroundColor: colorItem
}
return (
<div className="m-4">
<div className="max-w-sm rounded overflow-hidden shadow-lg w-48">
<div style={colorstyle} className="h-32">
</div>
<div className="px-6 py-4">
<p className="text-grey-darker">
{colorItem}
</p>
</div>
</div>
</div>
})}
If you call the parameter in the lambda 'backgroundColor', you can use this object short-notation:
{this.state.colorsArray.map(backgroundColor =>
<div className="m-4">
<div className="max-w-sm rounded overflow-hidden shadow-lg w-48">
<div style={{ backgroundColor }} className="h-32">
</div>
<div className="px-6 py-4">
<p className="text-grey-darker">
{backgroundColor}
</p>
</div>
</div>
</div>
}

Categories

Resources