I have a React component which renders an image. That image has to capture the onClick event, but it doesn't. There is no reason for this behavior. Here is the code:
class MyComponent extends React.Component {
imageClick = () => {
console.log('Click!!!!');
}
render () {
return (
<div>
<img src='/myfolder/myimage.png' onClick={this.imageClick} />
</div>
);
}
}
I can't see why it doesn't shows me back the 'Click!!!!' message in the browsers console when click on the image. It gives me back no error, no warning, no nothing. I'm using Chrome 62.0.3202 running on Linux Mint.
When isolated this code it works, but within boilerplate it does not, which is my case.
What am I missing here?
class MyComponent extends React.Component {
render () {
const imageClick = () => {
console.log('Click');
}
return (
<div>
<img src={require('/myfolder/myimage.png')} onClick={() => imageClick()} />
</div>
);
}
}
I've been playing with create-react-app and noticed that logo had pointer-events css style set to none which disables all the clicks. Not sure if that is your case. Just try to override that style in your img:
<img src='/myfolder/myimage.png' onClick={this.imageClick} style={{"pointer-events": "all"}} />
Well it does work in my case :
class MyComponent extends React.Component {
imageClick = () => {
console.log('Click!!!!');
}
render () {
return (
<div>
<img src='http://www.libpng.org/pub/png/img_png/obj_64x64.png' onClick={this.imageClick} />
</div>
);
}
}
ReactDOM.render(<MyComponent />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
And the same version with a prop (url) passed to the component, as well as as state modification triggered when you click the image, as those two are important in React :
class MyComponent extends React.Component {
constructor(props){
super(props);
this.state = {
clicked : false
}
}
imageClick = () => {
console.log('Click!!!!');
this.setState({
clicked: true
})
}
render () {
return (
<div>
<img src={ this.props.url } onClick={this.imageClick} />
{
this.state.clicked &&
<div>You clicked me!</div>
}
</div>
);
}
}
ReactDOM.render(<MyComponent url="http://www.libpng.org/pub/png/img_png/obj_64x64.png" />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
Hope this helps!
Your code looks fine and here is the working sample with image onClick. I have tested on my machine Chrome 16.0 working fine.
<!DOCTYPE html>
<html>
<head>
<title>React Image Click</title>
<meta charset="utf-8">
<script crossorigin src="https://unpkg.com/react#16.0.0/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16.0.0/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<script type="text/jsx">
class MyComponent extends React.Component {
imageClick = () => {
console.log('Click!!!!');
}
render () {
return (
<div>
<img src='/myfolder/myimage.png' onClick={this.imageClick} />
</div>
);
}
}
ReactDOM.render(
<MyComponent />,
document.getElementById("app")
);
</script>
</head>
<body>
<div id="app"></div>
</body>
</html>
ImageClick () {console.log('clicked');}
Just define the method as above and call the function like
onClick={this.ImageClick.bind(this)}
Hope it works
I have Found an alternative way to do that ....
I put image inside a button tag, and style that button to show nothing but image.
take a Look at my code :-)
<button style={{background:'none', border:'none'}}>
<img
style={{cursor:'pointer'}}
src={prova}
type="submit"
onclick={() => setTimeout(this.handleBtnClick(touched, errors),1)}
/>
</button>
Related
Is there a way to achieve conditionally rendered content below but instead of using {renderAuthButton()} in the return statement, I want to achieve running renderAuthButton() with onCLick instead?
class App extends Component {
// ...
render() {
let {isLoggedIn} = this.state;
const renderAuthButton = () => {
if (isLoggedIn) {
return <button>Logout</button>;
} else {
return <button>Login</button>;
}
}
return (
<div className="App">
<h1>
This is a Demo showing several ways to implement Conditional Rendering in React.
</h1>
{renderAuthButton()}
</div>
);
}
}
I don't really understand your need but to render conditionally, you can do something like that
state = {
show: false,
}
<div className="App">
<button onClick={() => this.setState((prev) => { show: !prev.show })}>Toggle</button>
{this.state.show && <MyComponent />}
</div>
I'm not completely sure what you're trying to do but this is how you would conditionally render content in react:
class App extends React.Component {
constructor(props){
super(props);
this.state = {
show: false
}
this.toggleShow = this.toggleShow.bind(this);
}
toggleShow(){
this.setState({show: ! this.state.show})
}
render(){
return (
<div>
<button onClick={this.toggleShow}>Filter Content</button>
{this.state.show ? (
<p>This content is conditionally shown</p>
) : (
<p>The content is now hidden</p>
)}
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById("root"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
here is my problem in the following code,
I have 3 block which contains a text "Yolo"
it is in the 1 block I look for when I click on "Move to the right" the text "Yolo" goes in the 2nd block and the same when I click again and goes in the 3rd block
Do you have an idea ,how to fix this?
import React from 'react';
import './index.css' export default class Demo extends React.Component {
constructor(props) {
super(props);;
};
render() {
return (
<div className="HereIsForFlex">
<button>Move to the Right</button>
<div className="test">
<p> yolo</p>
<div className="fruitsArrows">
</div>
</div>
<div className="test1">
</div>
<div className="test2">
</div>
</div>
);
};
}
You may simply store within component's local state the string you wish to move, the number of available 'slots' and current position of the string.
Then, simply use onClick event handler to increase current position:
const { render } = ReactDOM
class Demo extends React.Component {
constructor(props) {
super(props)
this.clickHandler = this.clickHandler.bind(this)
this.state = {currentPosition: 0, totalLength: 3, val: 'yolo'}
}
clickHandler(){
this.setState({currentPosition: (this.state.currentPosition + 1)%this.state.totalLength})
}
render() {
return (
<div>
<button onClick={this.clickHandler} >Move to the Right</button>
{
Array.from(
{length: this.state.totalLength},
(_,i) => (
<div key={i} className="slot">
<p>{i == this.state.currentPosition ? this.state.val : null}</p>
</div>
)
)
}
</div>
)}
}
render (<Demo />, document.getElementById('root'))
.slot{display:inline-block;vertical-align:top;text-align:center;margin-top:30px;margin-left:10px;width:50px;height:50px;background-color:grey;color:white;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><div id="root"></div>
Here's a working sandbox with the thing I believe you want to achieve: https://codesandbox.io/s/immutable-water-xy0n8
In my application, I have a requirement to render same data into multiple places via react.
So instead of rendering that via id (via below code), i want to use class tag.
ReactDOM.render(<App />, document.getElementById('app')); // Working
ReactDOM.render(<App />, $('.app')); // Not working.
My html is like below...
<div class="app" id="app"><div>
<div class="app"><div>
<div class="app"><div>
Update: below is my jsx file.
class PList extends React.Component {
static defaultProps = {
results: []
}
constructor(props) {
super(props);
this.state = {
results: this.props.results
};
}
render() {
return (
<ul>
{
this.state.results.map((item, i) => {
return <li>{item.Name}</li>
})
}
</ul>
);
}
}
var PRender = ReactDOM.render(<PList />, $('.app'));
function Professionals(data) {
PRender.setState({
results: data.Results
});
}
$('.app') - this is just an array, and ReactDOM.render requires single element as second parameter.
You can try as following if you need to render multiple App.
function App({index}) {
return `<div>App - ${index}</div>`;
}
document.querySelectorAll('.app').forEach((app, index) => ReactDOM.render(<App index={index + 1} />, app));
<html>
<div id="app">No ID assigned to App</div>
<div class="app"></div>
<div class="app"></div>
<div class="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
</html>
Here's the answer for your edition.
https://codesandbox.io/s/hopeful-payne-1tloe?fontsize=14
Same as #Alona's answer. I tried to use jQuery -> $('.app') which described on question.
function App({index}) {
return `<div>App - ${index}</div>`;
}
$.each($('.app'), (index, app) => ReactDOM.render(<App index={index + 1} />, app))
<html>
<div class="app" id="app"></div>
<div class="app"></div>
<div class="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
</html>
I have a component below: there are 2 usecases, when I click on the entire div some function is executed and when I click on just the <img>, some function is executed.
I have 2 props defined, onClick, when clicked on the entire div
and onIconClick when clicked on the img.
export default class List extends React.Component {
onClick() {
this.props.onClick();
}
onIconClick() {
this.props.onIconClick();
}
render() {
return (
<div style="width:200px, height: 200px" onClick={this.onClick.bind(this)}>
<img src="delete.png" onClick={this.onIconClick.bind(this)} />
</div>
);
}
}
here is the way I call the component:
export default class MyApp extends React.Component {
onClick() {
//some execution
}
onIconClick() {
//some other execution
}
render() {
return (
<List
onClick={this.onClick.bind(this)}
onIconClick={this.onIconClick.bind(this)}
/>
);
}
}
Now my issue is the this.onClick.bind(this) gets called all the time even when I click the image, hence I never get to this.onIconClick.bind(this).
I tried reversing the order:
<List onIconClick={this.onIconClick.bind(this)} onClick={this.onClick.bind(this)} />
still doesn't work, not sure what selection criteria I should use in order to distinguish between these 2 clicks.
Any ideas??
Try this:
class Parent extends React.Component {
constructor(props) {
super(props);
this.onClick = this.onClick.bind(this);
this.onIconClick = this.onIconClick.bind(this);
}
onClick() {
alert("Parent-onClick()");
}
onIconClick() {
alert("Parent-onIconClick()");
}
render() {
return (
<div>
<Child onClick={this.onClick} onIconClick={this.onIconClick} />
</div>
);
}
}
class Child extends React.Component {
constructor(props) {
super(props);
this.onClick = this.onClick.bind(this);
this.onIconClick = this.onIconClick.bind(this);
}
onClick() {
this.props.onClick();
}
onIconClick(e) {
e.stopPropagation();
this.props.onIconClick();
}
render() {
let styles = {
height: "500px",
backgroundColor: "blue",
paddingTop: "20px"
};
return (
<div onClick={this.onClick} className="img-wrapper" style={styles}>
<img
onClick={this.onIconClick}
src="https://via.placeholder.com/350x150"
alt="img"
/>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<Parent />, rootElement);
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root"><div>
The idea is using stopPropagation() method of the SyntheticEvent instance.
Your event handlers will be passed instances of SyntheticEvent, a
cross-browser wrapper around the browser’s native event. It has the
same interface as the browser’s native event, including
stopPropagation() and preventDefault(), except the events work
identically across all browsers.
If you find that you need the underlying browser event for some
reason, simply use the nativeEvent attribute to get it.
Using the SyntheticEvent 's methods allows our code to behave exactly the same across all browsers.
You can use e.stopPropagation(). If you want to use e.nativeEvent.stopImmediatePropagation(), you can use in the same line.
onIconClick(e) {
e.stopPropagation();
//e.nativeEvent.stopImmediatePropagation();
this.props.onIconClick();
}
Why When I press the button the caption doesn't change to 'Hide details' despite Name=false ?
let Name= true;
const Tekst= () =>{
Name=false;
Render();
};
const template = (
<div>
<h1>Visibility Toggle</h1>
<button onClick={Tekst}>{Name ? 'Show details' : 'Hide details'}</button>
</div>
);
const root= document.getElementById('app');
const Render = () =>ReactDOM.render(template, root);
Render();
Kindly note that your template jsx is hard coded and is only evaluated once when the program runs initially. So it just takes value of Name as true and becomes a constant. Rendering it again is not going to change in any way. You should use a component rather:
<Template />
let Name = true;
const Tekst = () => {
Name = !Name;
Render();
};
const Template = () => (
<div>
<h1>Visibility Toggle</h1>
<button onClick={Tekst}>
{Name ? "Show details" : "Hide details"}
</button>
</div>
);
const root = document.getElementById("app");
const Render = () => ReactDOM.render(<Template />, root);
Render();
<div id="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
This is how I would do that:
class Template extends React.Component {
constructor() {
super();
this.state = {name: true};
}
test = () => {
this.setState({name: !this.state.name});
};
render() {
return (
<div>
<h1>Visibility Toggle</h1>
<button onClick={this.test}>{this.state.name ? 'Show details' : 'Hide details'}</button>
</div>
)
}
}
ReactDOM.render(
<Template/>,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Because a component only renders when state or props change.
The way you defined your component, it has no props or state.
Try:
class Tekst extends React.Component {
constructor(props) {
super(props);
this.state = { Name: true };
this.toggle = this.toggle.bind(this);
}
toggle() {
this.setState({ Name: !this.state.Name });
}
render() {
return (
<div>
<h1>Visibility Toggle</h1>
<button onClick={this.toggle}>{ this.state.Name ? 'Show details' : 'Hide details'} />
</div>
);
}
}
I'm not sure which version of react or env you're on but this should work for most setups.
It appears the OP has a very limited understanding of React. This is not a criticism, we all have to start somewhere (and I would not consider myself much above beginner-level with React :) ). But if you want to make something with React, even just a toy example, I would strongly recommended reading through the introductory documentation at https://reactjs.org/docs/hello-world.html and the subsequent pages. In particular, I draw your attention to the following:
https://reactjs.org/docs/rendering-elements.html#updating-the-rendered-element (which explains why when a "React element" such as yours is rendered, it can never be updated except by re-rendering).
https://reactjs.org/docs/components-and-props.html#functional-and-class-components explains the basics of React Components, explaining that you need either a function or (for most non-trivial components) an ES6 Class. Once you have a React component, it will automatically re-render when its Props or State are altered. (As Salomao noted, your application contains neither.)