I am looking to pass an onClick function to each image element created using the map function. So that when a user clicks the thumbnail image it changes the main image to the thumbnail that was clicked.
Right now however it seems like the onClick function is being called without even being clicked and the image that is displayed is the last image in the array.
Also when I click the images nothing happens.
I feel like there may be multiple issues but not sure what.
let currentIndex = 0;
let changeImage = function(index) {
currentIndex = index;
}
const gallery =
product.images.length > 1 ? (
<Grid gap={2} columns={5}>
{product.images.map((img, index) => (
<GatsbyImage
image={img.gatsbyImageData}
key={img.id}
alt={product.title}
index={index}
onclick={changeImage(index)}
/>
))}
</Grid>
) : null;
The above code is affecting the below code.
<div>
{console.log('index is: ' + currentIndex)}
<GatsbyImage
image={product.images[currentIndex].gatsbyImageData}
alt={product.title}
/>
{gallery}
</div>
add the arrow function to the syntax like this ,
change onclick={changeImage(index)}
to this onclick={()=>changeImage(index)}
and for the rerendering .
i think you need to use state instead of let
change let currentIndex = 0;
to
const [currentIndex,setCurrentindex]=useState(0)
and currentIndex = index;
to setCurrentindex(index)
we use State to rerender the dom whenever there is a change , in your case the dom is not rerendering because you are not using state .
that should solve your problem
Related
Greetings
I have built a search and every time user types word it renders new checkboxes but new checkboxes don't work like they used to be none of the event listeners work on new checkboxes, when I'm clicking on checkboxes they just don't react, but in old ones, until search will render this they are working normally
//search in checkbox data
const checkOptions = (container, value, containerId) => {
for (let i = 0; i < props.unique[containerId].length; i++) {
let item = props.unique[containerId][i];
if (
props.unique[containerId][i] !== null &&
props.unique[containerId][i].includes(value)
) {
element = (
<label
onClick={(e) => {e.stopPropagation(); ifAnyChecked(e);}} key={i}>
<input onClick={(e) => {tableSearch(e);}} type="checkbox" value={item ? item : "empty"}/>
{item && item.length > 28 ? (
handleCheckbox(item)
) : (
<p>{item}</p>
)}
</label>
);
tempData += ReactDOMServer.renderToString(element);
}
}
container.innerHTML = tempData;
};
any idea what's happening?
Have you tried to use onChange event instead of onClick? As far as I know, input type checkbox doesn't have such an event like onClick.
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox
I used to get this problem when I was working with Vanilla JS whenever i render a new element then that element was not triggering my events. That was because they were generated on runtime so the event wasn't bound to that element. Now I think that thing is happening here as well. So I changed your code and put it inside a state now it is working. I hope I helped. Do let me know if this is not the solution that you were looking for but it solves your problem though
I put the html inside a state array then i mapped it out inside the newCheckBox div. I changed the input to controlled input with fieldValue state. Lastly i changed the new checkbox alert from onClick={alert("doesn't goes in")} to onClick={() => alert("I think its working now right?")}
Here is the complete code sandbox
https://codesandbox.io/s/polished-sea-vedvh?file=/src/App.js
I am trying to render an array of elements in react so that when you hover over an element it then filters the array of elements and re-renders with just the hovered element. Keeping position is buggy but not the worry for now.
It works but when the hover element is rendered it has no content
const [show, setShow] = useState(false);
const cards = [{key:"1",title:"elem1",content:"..."},{key:"2",title:"elem2",content:"..."},{key:"3",title:"elem3",content:"..."}]
const tempCards = []
My hover function returns
tempCards = [{key:"1",title:"elem1"}];
/// temp function allowing to work from button click
const changeShow = () => {
tempCards = cards.filter(item => item === cards[0]);
console.log(tempCards[0])
setShow(!show)
}
This is all working as it should but then when the element loads on the page no content shows
{show ? cards.map((item)=> {
return <CardSpinLeft
onClick={toggle}
key={item.key}
id={item.key}
image={item.img}
name={item.title}
title={item.title}
paragraph={item.content}
/>
}):
<CardSpinLeft
onClick={toggle}
key={tempCards.key}
id={tempCards.key}
image={tempCards.img}
name={tempCards.title}
title={tempCards.title}
paragraph={tempCards.content}
/>
}
not receiving any error's I even tried making the filter function async/await thinking its a loading issue. Only thing I can think is that react is pre-loading the content before it is there?
I am trying to show tooltip on mouse enter and hide on mouse leave.first i make a simple demo which is working fine.
https://codesandbox.io/s/exciting-shannon-4zuij?file=/src/list.js
above code working fine on hover it show's the tooltip and hide on leave.
see same concept i apply on a application.(this code is not working)
https://codesandbox.io/s/cool-liskov-8rvjw?file=/src/App.js
when I hover a item is show the tooltip.but it is not hiding the tooltip when you leaving the item.something went wrong.
const Student = ({students,clickHandler}) => {
console.log(students,"---ee")
const [selectedStudent,setSelectedStudent] = useState(null)
const onMouseHandler = (student,e)=>{
student.visibility = true
setSelectedStudent(student)
}
const onMouseLeaveHandler = (student)=>{
console.log('======',student)
student.visibility = false
setSelectedStudent(student)
}
return (
<ul className="student-container">
{
students && students.length > 0 ? students.map((student,index)=>{
return (
<li key={index} onClick={()=>{
clickHandler(student)
}}
onMouseLeave={()=>{
onMouseLeaveHandler(student)
}}
onMouseEnter={(e)=>{
onMouseHandler(student,e)
}} style={{position:'relative'}}>
<a><span>{student.name}</span></a>
{student.visibility? <ToolTip showToolTip={student.visibility} selectedStudent={selectedStudent}/>:null}
</li>
)
}):null
}
</ul>
);
};
export default Student;
Step too reproduce
Hover on first item Raj
and then try to hover sameer.both tooltip will display.I want only one tooltip will be display which is hovered.
I want my handlers should be in my functional component . I don't want to move these handler to parent component and pass handler as a props
In your demo it's also not work well, - one hide only when open another.
when you set student.visibility you not set state, so nothing has rerendered.
Then when you call setSelectedStudent you pass there just the same referance as was before, since it's the same object, so the state not changed, and again - nothing got rerendered.
What you have to do is pass the updated student in a new variable. like so:
setSelectedStudent({...student})
Then all should work
so I'm currently working on learning react.js, and I've run into an issue I haven't been able to move past.
So, the broad stroke is that I have a container which is meant to render a grid of images. If you select one of the images, you'll be able to change it to another image from a list of options.
Here is the potentially relevant portion of the Grid container which is rendering fine at this moment. If the full code in context helps, you can find it here: https://codepen.io/KrisSM/pen/wvvmoqg
_onBrigadePosSelection = slot => {
console.log("This was the division selected in Brigade Grid: " + slot);
this.props.onBrigadePosSelected(slot);
};
render() {
for (let i = 0; i < 15; i++) {
//each block is a separated so that they can be rendered as different rows in the return
if (i <= 4) {
rowOne.push(
<div key={i}>
<ImageButton
btnType={"Grid"}
imageSrc={this.props.icons[this.props.brigadeDesign[i]]}
clicked={() => this._onBrigadePosSelection(i)}
/>
</div>
);
}
if (i > 4 && i <= 9) {
rowTwo.push(
<div key={i}>
<ImageButton
btnType={"Grid"}
imageSrc={this.props.icons[this.props.brigadeDesign[i]]}
clicked={() => this._onBrigadePosSelection(i)}
/>
</div>
);
}
if (i > 9 && i <= 14) {
rowThree.push(
<div key={i}>
<ImageButton
btnType={"Grid"}
imageSrc={this.props.icons[this.props.brigadeDesign[i]]}
clicked={() => this._onBrigadePosSelection(i)}
/>
</div>
);
}
}
So, when an image button is selected, it fires the onBrigadePosSelection function, which returns the selected button to the container for the grid where this function is then hit.
onBrigadePosSelected = slot => {
this.setState({ selectedDivision: slot });
console.log("This is the selected division: " + slot);
};
So, thus far, everything works. The grid renders and when a button is hit, this console log correctly states which button was hit. But this is where things start to get odd. When the state changes, their is a re-render of course, but after that re-render, selectedDivision becomes undefined.
Looking at your codes, I think the problem comes from these lines:
clicked={() => this._onBrigadePosSelection(i)}
The reason is that i will keep changing for each iteration, but () => this._onBrigadePosSelection(i) is dynamically called function.
It means that whenever you click the button, it'll get the latest value of i (or garbage or undefined) because i was garbage collected already.
I would suggest you pass the function this._onBridgePosSelection as props and call it inside the <ImageButton /> component instead.
<ImageButton
btnType={"Grid"}
imageSrc={this.props.icons[this.props.brigadeDesign[i]]}
index={i}
onBrigadePosSelection={this._onBrigadePosSelection}
/>
Then inside <ImageButton /> component, you can call it with this:
this.props.onBrigadePosSelection(this.props.index)
Basically, I'm trying to clone an element and change its aria-label within React.cloneElement. I've got a component - ButtonArrows - that creates two Button components, one with an arrow icon pointing left, and one pointing right. I'd like to be able to programmatically change the aria-label, but the hyphen throws an error.
Here's some code showing what I'm trying to do:
const ButtonArrows = ({leftArrow, rightArrow, ...props})
const prevButton = (
<Button
aria-label="Previous",
icon={leftArrow}
/>
);
const nextButton = React.cloneElement(prevButton, {
//this is where the problem is:
aria-label="Next",
icon={rightArrow}
});
return(<div {...props}>{prevButton}{nextButton}</div>);
}
and obviously I can't do aria-label="Next" because of the hyphen.
Any suggestions? React unfortunately doesn't have anything like htmlFor (to stand in for html-for) when it comest to aria labels. Should I just put an ariaLabel prop on Button and pass it down, or is there a way to do it directly with cloneElement that I'm missing?
You should be able to use a plain JavaScript object here:
const nextButton = React.cloneElement(prevButton, {
'aria-label': 'Next',
icon: rightArrow
});
const ButtonArrows = ({leftArrow, rightArrow, ...props})
const prevButton = (
<Button
ariaLabel="Previous",
icon={leftArrow}
/>
);
const nextButton = React.cloneElement(prevButton, {
//this is where the problem is:
ariaLabelledby="Next",
icon={rightArrow}
});
return(<div {...props}>{prevButton}{nextButton}</div>);
}
change aria-label to ariaLabel