class BlogPost extends React.Component{
//getInitialState
constructor(){
super();
this.onLike = this.onLike.bind(this);
this.state = {
like :0
}
}
onLike(){
this.setState({
like: this.state.like++
});
}
render(){
var postListItem = this.props.postList.map(function(post){
return <li> {post} </li>
});
return (
<div className="blogPost">
<h2>Posts</h2>
<ul>{postListItem}</ul>
<button onClick={(e) => {this.onLike}}>{this.state.like}</button>
</div>
);
}
}
Nothing happens on clicking Button.
There is no function on button and index.js has added Empty Function to it. IDK why?please explain
In this case you need remove arrow function ((e) => { }), it is not necessary here, because you bind this in constructor., also inside onLike change this.state.like++ to this.state.like + 1 because you can't mutate state
<button onClick={ this.onLike }>{this.state.like}</button>
class BlogPost extends React.Component{
constructor(){
super();
this.onLike = this.onLike.bind(this);
this.state = {
like: 0
}
}
onLike(){
this.setState({
like: this.state.like + 1
});
}
render(){
var postListItem = this.props.postList.map(function(post){
return <li> {post} </li>
});
return (
<div className="blogPost">
<h2>Posts</h2>
<ul>{ postListItem }</ul>
<button onClick={ this.onLike }>{this.state.like}</button>
</div>
);
}
}
ReactDOM.render(<BlogPost postList={ [] } />, document.getElementById('container'));
<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="container"></div>
I think you're not invoking the onLike function in the annonymous function you're passing to onClick.
Try this:
<button onClick={(e) => {this.onLike()}}>{this.state.like}</button>
Note the () after onLike.
Related
The edit function does not change the editing in state to true.
I don't know what to do:
class Note extends React.Component {
constructor (props) {
super(props)
this.state = {
editing: false
}
}
/**edit() {
this.setState = ({
editing: true
})**/
}
remove() {
alert ("removed")
}
save() {
alert ("saved")
}
renderForm() {
return (
<div className="note">
<form>
<textarea/>
<button onClick={this.save}> click </button>
</form>
</div>
)
}
renderDisplay() {
return (
<div className="note">
<p> Learn React </p>
<span>
<button onClick={this.edit} id="edit"> Edit </button>
<button onClick={this.remove} id="remove"> Delete </button>
</span>
</div>
)
}
render() {
return this.state.editing ? this.renderForm() : this.renderDisplay()
}
}
You should change this:
this.setState = ({
editing: true
})
to this:
this.setState({
editing: true
})
Also, you should bind edit method or use an arrow function instead. It's required because in JavaScript function context is defined while calling the function, not while defining it.
Here you can check an example.
I have a component which displays images on click of a button. These images when get displayed on the screen, I want to apply an onClick listener to them such that the image that I click on gets displayed on the whole screen.
Code:
class App extends React.Component{
constructor(props){
super(props);
this.state={
images:[],
pano:'',
name:'',
list:[]
}
this.loadImages=this.loadImages.bind(this);
this.loadOne=this.loadOne.bind(this);
}
loadImages(){
console.log("load");
var that=this;
$.ajax({
type:'GET',
url:'https://demo0813639.mockable.io/getPanos',
success:function(result){
var images=that.state.images;
for(var i=0;i<result.length;i++){
that.state.images.push({"pano":result[i].pano,"name":result[i].name});
}
that.setState({
images:images
})
}
})
}
loadOne(url){
console.log("hi")
}
render(){
var list=this.state.list;
list=this.state.images.map(function(result){
//console.log(result.name);
return(<div className="box">
<div className="label">{result.name}</div>
<img src={result.pano} className="image"/>
</div>
)
})
return(
<div>
<button onClick={this.loadImages}>Click</button>
<div onClick={this.loadOne(this,this.props.result.pano)}>{list}</div>
</div>
);
}
}
loadOne() is the function which gets called after clicking on an image. I get the error:
cannot read property pano of undefined
And if I do like this:
render(){
var list=this.state.list;
list=this.state.images.map(function(result){
return(<div className="box">
<div className="label">{result.name}</div>
<img src={result.pano} className="image" onClick={this.loadOne(this,this.props.result.pano)}/>
</div>
)
})
return(
<div>
<button onClick={this.loadImages}>Click</button>
<div >{list}</div>
</div>
);
}
then I get the error:
cannot read property loadOne of undefined.
So, how can I pass specific image url to my function?
Issue with second snippet is:
1- You forgot to bind the map callback method, use arrow function:
var list = this.state.list;
list = this.state.images.map((result) => { //here
.....
2- You missed the bind word here:
onClick = {this.loadOne.bind(this,result.pano)}
3- Instead of this.props.result.pano it should be result.pano.
Full code:
var list = this.state.list;
list = this.state.images.map((result) => {
return(
<div className="box">
<div className="label">{result.name}</div>
<img src={result.pano} className="image" onClick={this.loadOne.bind(this,result.pano)}/>
</div>
)
})
Working Code:
class App extends React.Component{
constructor(props){
super(props);
this.state={
images:[],
pano:'',
name:'',
list:[]
}
this.loadImages=this.loadImages.bind(this);
this.loadOne=this.loadOne.bind(this);
}
loadImages(){
var that=this;
$.ajax({
type:'GET',
url:'https://demo0813639.mockable.io/getPanos',
success:function(result){
var images=that.state.images;
for(var i=0;i<result.length;i++){
that.state.images.push({"pano":result[i].pano,"name":result[i].name});
}
that.setState({
images:images
})
}
})
}
loadOne(pano){
console.log('pano', pano);
}
render(){
var list = this.state.list;
list = this.state.images.map((result)=>{
return(
<div className="box">
<div className="label">{result.name}</div>
<img src={result.pano} className="image" onClick={this.loadOne.bind(this,result.pano)}/>
</div>
)
})
return(
<div>
<button onClick={this.loadImages}>Click</button>
<div >{list}</div>
</div>
);
}
}
ReactDOM.render(<App/>,document.getElementById('container'));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<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='container'/>
Check this answer: Why is JavaScript bind() necessary?
You need to bind you click function to that image.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
images: [],
pano: '',
name: '',
list: []
}
this.loadImages = this.loadImages.bind(this);
//The loadOne cant be bound to this here, it needs a
//bind for each image. Effectivly creating one version of loadOne per image.
}
loadImages() {
$.ajax({
type: 'GET',
url: 'https://demo0813639.mockable.io/getPanos',
success:(result) => {
var images = this.state.images;
for (var i = 0; i < result.length; i++) {
this.state.images.push({ url: result[i].pano, name: result[i].name });
}
this.setState({
images: images
})
}
})
}
loadOne(url, mouseEvent) {
console.log(url);
}
render() {
//This can get extracted to a custom component
var imagesList = this.state.images.map((image, i) => {
return (<div key={i} className="box" >
<div className="label">{image.name}</div>
{/*This is where the bind/curry should be */}
<img onClick={this.loadOne.bind(this, image.url)} src={image.url} className="image" />
</div>
)
});
return (
<div>
<button onClick={this.loadImages}>Click</button>
<div>{imagesList}</div>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('container'));
Your clickhandler (loadOne) will then be called with the result.pano and the event as second argument passed in by react.
http://jsbin.com/zokugitopa/1/edit?js,output
I have the following code:
index.js
class App extends React.Component {
constructor() {
super();
this.state = {
homeLink: "Home"
};
}
onGreet() {
alert("Hello!");
}
onChangeLinkName(newName) {
this.setState({
homeLink: newName
});
}
render() {
return (
<div className="container">
<div className="row">
<div className="col-xs-10 col-xs-offset-1">
<Header homeLink={this.state.homeLink}/>
</div>
</div>
<div className="row">
<div className="col-xs-10 col-xs-offset-1">
<Home
name={"Max"}
initialAge={27}
greet={this.onGreet}
changeLink={this.onChangeLinkName.bind(this)}
initialLinkName={this.state.homeLink}
/>
</div>
</div>
</div>
);
}
}
And
Home.js
export class Home extends React.Component {
constructor(props) {
super();
this.state = {
age: props.initialAge,
status: 0,
homeLink: props.initialLinkName
};
}
onMakeOlder() {
this.setState({
age: this.state.age + 3
});
}
onChangeLink() {
this.props.changeLink(this.state.homeLink);
}
onHandleChange(event) {
this.setState({
homeLink: event.target.value
});
}
render() {
return (
<div>
<p>In a new Component!</p>
<p>Your name is {this.props.name}, your age is {this.state.age}</p>
<p>Status: {this.state.status}</p>
<hr/>
<button onClick={() => this.onMakeOlder()} className="btn btn-primary">Make me older!</button>
<hr/>
<button onClick={this.props.greet} className="btn btn-primary">Greet</button>
<hr/>
<input type="text" value ={this.state.homeLink}
onChange={(event) => this.onHandleChange(event)}/>
<button onClick={this.onChangeLink.bind(this)} className="btn btn-primary">Change Header Link</button>
</div>
);
}
}
Would onChange in the input tag be triggered as soon as I write something in the input field and update to state? I can't see the state change in the React Developer Tool extension in Chrome when I write something in the input field.
When I click the button this.onChangeLink it triggers the onChangeLink function. The onChangeLink doesn't seem to take any arguments since the brakets are empty, still I'm able to pass this.state.homeLink to this.props.changeLink inside the onChangeLink function. this.props.changeLink which is also a function in index.js takes an argument newName. I guess this is where the bind(this) comes in. What does bind(this) do? Could I rewrite it with a fat arrow function like (event) => this.onChangeLink(event)?
bind is a function in Function.prototype which returns a function object which is bound to the current this.
onClick={this.onChangeLink.bind(this)}
Here onClick function will be passed as a handler with the current context.
An arrow function does not create a new this context at all. The this will refer to the context in which the function is defined.
An arrow function does not create its own this context, so this has its original meaning from the enclosing context.
onChange={(event) => this.onChangeLink(event)}
Here even though onChangeLink is not bound, it is called within an arrow function within the same this context.
So.. yes, you can replace it with a fat arrow notation to get the same effect. Although you have to rewrite the list of arguments in this case twice.
You dont need to onChangeLink in Home component. You can directly pass the value to App component.
class Home extends React.Component {
constructor(props) {
super();
this.state = {
age: props.initialAge,
status: 0,
homeLink: props.initialLinkName
};
}
onMakeOlder() {
this.setState({
age: this.state.age + 3
});
}
onHandleChange(event) {
this.setState({
homeLink: event.target.value
});
}
render() {
return (
<div>
<input type="text" value ={this.state.homeLink}
onChange={(event) => this.onHandleChange(event)}/>
<button onClick={()=>this.props.changeLink(this.state.homeLink)} className="btn btn-primary">Change Header Link</button>
</div>
);
}
}
class App extends React.Component {
constructor() {
super();
this.state = {
homeLink: "Home"
};
}
onGreet() {
alert("Hello!");
}
onChangeLinkName(newName) {
this.setState({
homeLink: newName
});
}
render() {
console.log(this.state)
return (
<div className="container">
<div className="row">
<div className="col-xs-10 col-xs-offset-1">
</div>
</div>
<div className="row">
<div className="col-xs-10 col-xs-offset-1">
<Home
name={"Max"}
initialAge={27}
greet={this.onGreet}
changeLink={this.onChangeLinkName.bind(this)}
initialLinkName={this.state.homeLink}
/>
</div>
</div>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("app"))
<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="app"></div>
After having read about the bind requirement for methods to be bound to a React ES6 class, I am still having some difficulty with this example:
class ProductList extends React.Component {
constructor(props) {
super(props);
this.state = { products: [] };
this.updateState = this.updateState.bind(this);
}
componentDidMount() {
this.updateState();
}
handleProductUpvote(productId) {
Data.forEach((item) => {
if (item.id === productId) {
item.votes = item.votes + 1;
return;
}
});
this.updateState();
}
updateState() {
const products = Data.sort((a,b) => {
return b.votes - a.votes;
});
this.setState({ products });
}
render() {
const products = this.state.products.map((product) => {
return (
<Product
key={'product-' + product.id}
id={product.id}
title={product.title}
description={product.description}
url={product.url}
votes={product.votes}
submitter_avatar_url={product.submitter_avatar_url}
product_image_url={product.product_image_url}
onVote={this.handleProductUpvote}
/>
);
});
return (
<div className='ui items'>
{products}
</div>
);
}
}
class Product extends React.Component {
constructor() {
super();
this.handleUpvote = this.handleUpvote.bind(this);
}
handleUpvote() {
this.props.onVote(this.props.id);
}
render() {
return (
<div className='item'>
<div className='image'>
<img src={this.props.product_image_url} />
</div>
<div className='middle aligned content'>
<div className='header'>
<a onClick={this.handleUpvote}>
<i className='large caret up icon'></i>
</a>
{this.props.votes}
</div>
<div className='description'>
<a href={this.props.url}>
{this.props.title}
</a>
</div>
<div className='extra'>
<span>Submitted by:</span>
<img
className='ui avatar image'
src={this.props.submitter_avatar_url}
/>
</div>
</div>
</div>
);
}
}
ReactDOM.render(
<ProductList />,
document.getElementById('content')
);
This returns
Uncaught TypeError: this.updateState is not a function(...) at handleProductUpvote
Is the initialized binding not sufficient in this case?
Whenever you see this issue, you don't want to be adding the bind to the method that it's trying to call right then, but the method that you are inside of when the "this.xxx not defined" issue occurs.
Currently, it's getting the function handleProductUpvote just fine - but it's calling it in the wrong object context. So you need to do the same thing as you did with updateState in the constructor, but with that function. Though I have limited react knowledge I believe it's common to do that for every function that's used as an event listener or callback.
Below is my code...
<ul className="no-style board__list">
{Object.keys(today.books).map(function(id) {
var refBook = today.books[id][0];
return (
<li key={refBook._id} className="board__list-item">
<div className="container flexrow">
<div className="flexrow__fit-2">{refBook.book_no}</div>
<div className="flexrow__org">
<span className="board__icon-wrap">
{refBook.memo
? (<i className="fa fa-flag" style={{color:"#F9AB9F"}}></i>)
: null
}
</span>
{refBooking.memo
? (<div className="memo_dialog">{refBook.memo}</div>)
: null
}
</div>
</div>
</li>
);
})}
</ul>
I have a object books array and I create a fa-flag icon for each book.
What I want is to show different memo dialog when mouse hover on each flag icon.
I know how to do it with query but how can I do this in react way not using jquery?
I'm not sure what are you trying to achieve but this example might be useful for you
class Book extends React.Component {
constructor(props){
super(props);
this.handleOver = this.handleOver.bind(this);
}
handleOver(name){
this.props.over(this.props.name)
}
render(){
return <div onMouseOver={this.handleOver}>{this.props.name}</div>
}
}
class BookList extends React.Component {
constructor(props){
super(props);
this.mouseOver = this.mouseOver.bind(this);
this.state = {
books: ['hello', 'amazing', 'world'],
memo: ''
}
}
mouseOver(name){
this.setState({memo: name})
}
render(){
const bookList = this.state.books.map((book, index)=>{
return <Book key={index} name={book} over={this.mouseOver}/>
});
return <div>
{bookList}
<hr/>
<div>{this.state.memo}</div>
</div>
}
}
React.render(<BookList />, document.getElementById('container'));
Also fiddle example.
I hope it will help you. Thanks
I suggest you to use isHovered state variable, to store hover state.
We are displaying some component(in your case it would be dialog box), if isHovered is true and hide it when this variable is false.
When we will hover on link element, we will trigger handleEnter function to set isHovered variable to true.
Similarly, when we are moving cursor out of link element, we are triggering handleLeave function to set isHovered variable to false.
Example:
class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
isHovered: false,
};
}
handleEnter() {
this.setState({
isHovered: true
});
}
handleLeave() {
this.setState({
isHovered: false
});
}
render() {
return (
<div>
<a
onMouseEnter={this.handleEnter.bind(this)}
onMouseLeave={this.handleLeave.bind(this)}
>Link</a>
{this.state.isHovered ? (
<div className="box">A component</div>
) : (
<div />
)}
</div>
);
}
}
Also, you can see demo at CodePen.