REACT component can work with onClink event - reactjs

I'm new in REACT, I'm trying to make a slider, so I need this <img> to act like a button, I tried to use an onClick event to test the functionality by sending a simple console.log, but it does nothing at all!, I really canĀ“t find the problem, it sends no error, it just didn't work.
I have another <img> with an onClick event that works just fine, in another component, so I can't tell what's the problem here.
Also, I thought maybe was my console.log so I call an Alert, but no, that didn't work either. Could anyone help me?
The code looks something like this:
const SliderInstructors = () => {
const siguiente = () => {
console.log('Siguiente');
alert('You clicked me!');
};
const anterior = () => {
console.log('Anterior');
alert('You clicked me!');
};
return(
<> {/* Controles */}
<div className="controls">
<img onClick={() => anterior} src={ArrowLeft} style={{'pointer-events': "all"}} alt="Before"/>
<img onClick={() => siguiente} src={ArrowRight} style={{'pointer-events': "all"}} alt="After"/>
</div>
</>
)
}
export default SliderInstructors;
This is a component which I send to call to a Page, like this
import SliderInstructors from '../components/SliderInstructors';
function AboutUs() {
const { t} = useTranslation();
return (
<><div className="instructorsAbout">
<h2>{t('about.instructor')}</h2>
<div className="infoInstructors">
<SliderInstructors/>
</div>
</div>
</>
)
}
export default AboutUs;
I thought maybe was my styles but I deleted the styles from them component and nothing, also I tried to put the component directly in the App.js but nop, so I really don't know where to keep looking at.

<img onClick={() => anterior()} src={ArrowLeft} style={{'pointer-events': "all"}} alt="Before"/>
<img onClick={() => siguiente()} src={ArrowRight} style={{'pointer-events': "all"}} alt="After"/>
or
<img onClick={anterior} src={ArrowLeft} style={{'pointer-events': "all"}} alt="Before"/>
<img onClick={ siguiente} src={ArrowRight} style={{'pointer-events': "all"}} alt="After"/>

Try calling the anterior and siguiente functions without anonymous functions on onClick.
<img onClick={anterior} src={ArrowLeft} style={{'pointer-events': "all"}} alt="Before"/>
<img onClick={siguiente} src={ArrowRight} style={{'pointer-events': "all"}} alt="After"/>

Related

React slick slide not clickable

I am using react slick for making slides of poll. I am facing issue while clicking the poll option. Click gets fired after two clicks.
I think touch start is the issue here.
Not sure if it's like your code but the console logs the text when I click on the first image:
const ReactSlick = (props) => {
var settings = {
dots: true
};
return (
<div className="container">
<Slider {...settings}>
<div>
<img onClick={() => console.log("Clicked !")} src="http://placekitten.com/g/400/200" />
</div>
<div>
<img src="http://placekitten.com/g/400/200" />
</div>
</Slider>
</div>
);
}
```;

i want the data that is in form component to be shown when pickup button is clicked

i want the data that is in form component to be shown when pickup button is clicked. the data from myvehicles to be entered inside the pickup component, when the yes or no button is clicked. i have tried like this but it doesnot work.
import React,{ useState } from 'react'
import './Pickup.css'
import logo from './images/logo.png'
import { Link, useHistory } from "react-router-dom";
import InfoYes from './InfoYes'
import InfoNo from './InfoNo'
function Pickup() {
const [showInfoYes, setShowInfoYes] = useState(false);
const [showInfoNo, setShowInfoNo] = useState(false);
const history = useHistory()
return (
<div className="pickup">
<div className="vehicles__navbar">
<Link to="/" className="header__link">
<img
className="navbar__logo"
src={logo}
alt="logo"
/>
</Link>
<button className="navbar__button" onClick={() => history.push('/')}>Logout</button>
</div>
<div className="pickup__info">
<h1 className="h1__pickup">do you want bluebook pickup service?</h1>
<div className="pickup__button">
<button className="yes__button" onClick={() => setShowInfoYes(!showInfoYes)}>yes</button>
<button className="no__button" onClick={() => setShowInfoNo(!showInfoNo)}>no</button>
</div>
{showInfoYes && <InfoYes setShowInfoYes={setShowInfoYes} />} </div>
{showInfoNo && <InfoNo setShowInfoNo={setShowInfoNo} />}
</div>
)
}
export default Pickup
I think you may be able to achieve this through conditional rendering.
Which involves if statements and true & false conditions.
Please look at this documentation to see how this works. Documentation
(Reactjs.org has really great documentation, I really encourage you go through it.)
No where in your code, I see your state to be set TRUE for it to render.
You'll need to create an onClick handler to set this to true or false.
A quick example would be:
const [userClicked, setUserClicked] = useState(false);
{ userClicked ?
( <button onClick={() => setUserClicked(false)> No </button>
) : (
<button onClick={() => setUserClicked(true)> Yes </button>
)}
This is a shorthand of a ternary operator to produce an if/then statement in react.
It would be the easiest to accomplish your goal, although I do suggest that you research a little bit more on it!
{userClicked ? ( ) : ( ) }
You could also take out:
const [showInfoYes, setShowInfoYes] = useState(false);
const [showInfoNo, setShowInfoNo] = useState(false);
It's a bit redundant as you're trying to achieve something that could be done in a singular state.

onClick on <li> does't trigger

I'm having a headache trying to understand why my onClick on a <li> doesn't trigger
I'm using react
I'm posting here the snippet of code:
This is the list creation:
<div className="countryList">
<ul>
{_adminCodes.map((item) => (
<li
style={{ cursor: "pointer" }}
onClick={handleListCountryClick}
className="countryLi">{item.name}
</li>
))}
</ul>
</div>
And this is the function handleListCountryClick:
const handleListCountryClick = () => {console.log("I'm a country!")}
Any advice would be appreciated!
EDIT:
I've tryied:
onClick={handleListCountryClick()}
onClick={() => handleListCountryClick()}
EDIT 2: This component (map) is included in a father component (graphs), if I try to trigger the onClick in the map component it runs the function, instead if I try to trigger the onClick in the father component (graphs) it doesn't work
Here's a stackblitz demo
Try calling the function with (), by using handleListCountryClick your are referencing the function instead of executing it.
onClick={() => {handleListCountryClick()}}
Dang ok are you using a class component then try:
onClick={() => {this.handleListCountryClick()}}
Sorry I tried I would need to see more code to help further.
Test this:
onClick={() => {console.log('I worked!!')}}
if that works then there is a reference error to the function.
You can try by updating your code to "onClick={() => handleListCountryClick}"
Edit:
This is what I have tried in codeSandbox and getting below results:
class Country extends React.Component {
render() {
const adminCodes = ["India", "USA", "UK", "UAE"];
return (
<div>
<ul>
{adminCodes.map((item) => (
<li
key={item}
style={{ cursor: "pointer" }}
onClick={() => handleListCountryClick(item)}
>
{item}
</li>
))}
</ul>
</div>
);
}
}
const handleListCountryClick = (item) => {
console.log(`I'm a ${item}!`);
};
export default Country;
Results (on click of listitems in same order):
I'm a India!
I'm a USA!
I'm a UK!
I'm a UAE!
usually the onClick is written onClick={() => onClickFunction()} SO the fact you tried these solutions makes me think there's a problem somewhere else. Can you please edit the question and write more of the component code so we can understand better? Thank You.

state is not updating when the component re renders?

I'm making a Nextjs flashcard app. I'm passing a deck structure like this:
const deck = {
title: 'React 101',
flashcards: [flashcardOne, flashcardTwo],
};
as props to the Deck component. This component shows the first card in flashcards and a "next" button to increment the index and showing the next card in flashcards.
The Card component is very simple and shows the front and the back of the card depending of the state front.
This is what I got so far and it's working but if I click "next" when the card is showing the answer (flashcard.back), the next card is going to appear with the answer. And I'm not sure why, isn't the Card component re rendering when I click "next"? And if the component re renders, front is going to be set to true?
export default function Deck({ deck }) {
const [cardIndex, setCardIndex] = useState(0);
const { title, flashcards } = deck;
return (
<div className={styles.container}>
<main className={styles.main}>
<h1 className={styles.title}>{title}</h1>
{cardIndex < flashcards.length ? (
<>
<div className={styles.grid}>
<Card flashcard={flashcards[cardIndex]} />
</div>
<button onClick={() => setCardIndex((cardIndex) => cardIndex + 1)}>
Next
</button>
</>
) : (
<>
<div>End</div>
<button>
<Link href='/'>
<a>Go to Home</a>
</Link>
</button>
<button onClick={() => setCardIndex(0)}>Play again</button>
</>
)}
</main>
</div>
);
}
export function Card({ flashcard }) {
const [front, setFront] = useState(true);
return (
<>
{front ? (
<div
className={`${globalStyles.card} ${styles.card}`}
onClick={() => setFront(false)}
>
<p className={styles.front}>{flashcard.front}</p>
</div>
) : (
<div
className={`${globalStyles.card} ${styles.card}`}
onClick={() => setFront(true)}
>
<p className={styles.back}>{flashcard.back}</p>
</div>
)}
</>
);
}
When state changes, the card will re-render, but it will not re-mount. So, existing state will not be reset.
Call setFront(true) when the flashcard prop has changed:
const [front, setFront] = useState(true);
useLayoutEffect(() => {
setFront(true);
}, [flashcard]);
I'm using useLayoutEffect instead of useEffect to ensure front gets set ASAP, rather than after a paint cycle (which could cause flickering).
You can also significantly slim down the Card JSX:
export function Card({ flashcard }) {
const [front, setFront] = useState(true);
const face = front ? 'front' : 'back';
return (
<div
className={`${globalStyles.card} ${styles.card}`}
onClick={() => setFront(!front)}
>
<p className={styles[face]}>{flashcard[face]}</p>
</div>
);
}
Okay, I guess I had the same issue. Since you're using functional components, and you're re-using the same component or in better words, you're not unmounting and remounting the component really, you're just changing the props, this happens. For this, you need to do useEffect() and then setFront(true).
Here's the code I used in my App.
useEffect(() => {
setFront(true);
}, [flashcard]);
This is what I have used in my Word.js file.

Unexpected Behavior After State Change in React Component

RenderImages = (): React.ReactElement => {
let selected = this.state.results.filter(x=>this.state.selectedGroups.includes(x.domain))
console.log(selected)
return(
<div className="results_wrapper">
{selected.map((r,i)=>{
let openState = (this.state.selectedImage==i)?true:false;
return(
<RenderPanel panelType={PanelType.large} openState={openState} title={r.domain+'.TheCommonVein.net'} preview={(openIt)=>(
<div className="result" onClick={openIt} style={{ boxShadow: theme.effects.elevation8}}>
<img src={r.url} />
</div>
)} content={(closeIt)=>(
<div className="panel_wrapper">
<div className="panel_content">{r.content}</div>
{this.RenderPostLink(r.domain,r.parent)}
<div onClick={()=>{
closeIt();
this.setState({selectedImage:2})
console.log('wtfff'+this.state.selectedImage)
}
}>Next</div>
<img src={r.url} />
</div>
)}/>
)
})}
</div>
)
}
When I change the state of 'selectedImage', I expect the variable 'openState' to render differently within my map() function. But it does not do anything.
Console.log shows that the state did successfully change.
And what is even stranger, is if I run "this.setState({selectedImage:2})" within componentsDidMount(), then everything renders exactly as expected.
Why is this not responding to my state change?
Update
I have tried setting openState in my component state variable, but this does not help either:
RenderImages = (): React.ReactElement => {
let selected = this.state.results.filter(x=>this.state.selectedGroups.includes(x.domain))
console.log(selected)
let html = selected.map((r,i)=>{
return(
<RenderPanel key={i} panelType={PanelType.large} openState={this.state.openState[i]} title={r.domain+'.TheCommonVein.net'} preview={(openIt)=>(
<div className="result" onClick={openIt} style={{ boxShadow: theme.effects.elevation8}}>
<img src={r.url} />
</div>
)} content={(closeIt)=>(
<div className="panel_wrapper">
<div className="panel_content">{r.content}</div>
{this.RenderPostLink(r.domain,r.parent)}
<div onClick={()=>{
closeIt();
let openState = this.state.openState.map(()=>false)
let index = i+1
openState[index] = true;
this.setState({openState:openState},()=>console.log(this.state.openState[i+1]))
}
}>Next</div>
<img src={r.url} />
</div>
)}/>
)
})
return(
<div className="results_wrapper">
{html}
</div>
)
}
https://codesandbox.io/s/ecstatic-bas-1v3p9?file=/src/Search.tsx
To test, just hit enter at the search box. Then click on 1 of 3 of the results. When you click 'Next', it should close the pane, and open the next one. That is what I'm trying to accomplish here.
#Spitz was on the right path with his answer, though didn't follow through to the full solution.
The issue you are having is that the panel's useBoolean doesn't update it's state based on the openState value passed down.
If you add the following code to panel.tsx, then everything will work as you described:
React.useEffect(()=>{
if(openState){
openPanel()
}else{
dismissPanel();
}
},[openState, openPanel,dismissPanel])
What this is doing is setting up an effect to synchronize the isOpen state in the RenderPanel with the openState that's passed as a prop to the RenderPanel. That way while the panel controls itself for the most part, if the parent changes the openState, it'll update.
Working sandbox
I believe it's because you set openState in your map function, after it has already run. I understand you think the function should rerender and then the loop will run once more, but I think you'll need to set openState in a function outside of render.
The problem is that even though you can access this.state from the component, which is a member of a class component, there's nothing that would make the component re-render. Making components inside other components is an anti-pattern and produces unexpected effects - as you've seen.
The solution here is to either move RenderImages into a separate component altogether and pass required data via props or context, or turn it into a normal function and call it as a function in the parent component's render().
The latter would mean instead of <RenderImages/>, you'd do this.RenderImages(). And also since it's not a component anymore but just a function that returns JSX, I'd probably rename it to renderImages.
I tire to look at it again and again, but couldn't wrap my head around why it wasn't working with any clean approach.
That being said, I was able to make it work with a "hack", that is to explicitly call openIt method for selectedImage after rendering is completed.
RenderImages = (): React.ReactElement => {
let selected = this.state.results.filter((x) =>
this.state.selectedGroups.includes(x.domain)
);
return (
<div className="results_wrapper">
{selected.map((r, i) => {
let openState = this.state.selectedImage === i ? true : false;
return (
<RenderPanel
key={i}
panelType={PanelType.medium}
openState={openState}
title={r.domain + ".TheCommonVein.net"}
preview={(openIt) => {
/* This is where I am making explicit call */
if (openState) {
setTimeout(() => openIt());
}
/* changes end */
return (
<div
className="result"
onClick={openIt}
style={{ boxShadow: theme.effects.elevation8 }}
>
<img src={r.url} />
</div>
);
}}
content={(closeIt) => (
<div className="panel_wrapper">
<div className="panel_content">{r.content}</div>
{this.RenderPostLink(r.domain, r.parent)}
<div
onClick={() => {
closeIt();
this.setState({
selectedImage: i + 1
});
}}
>
[Next>>]
</div>
<img src={r.url} />
</div>
)}
/>
);
})}
</div>
);
};
take a look at this codesandbox.

Resources