Reputation: 6880
I am trying to do the tutorial: https://facebook.github.io/react/docs/tutorial.html
import React, { PropTypes } from 'react';
import classnames from 'classnames';
import styles from './CommentBox.css';
import withStyles from '../../decorators/withStyles';
import Link from '../../utils/Link';
import $ from 'jquery';
@withStyles(styles)
class CommentBox extends React.Component {
constructor() {
super();
this.state = {data: []};
}
loadCommentsFromServer() {
$.ajax({
url: this.props.url,
dataType: 'json',
cache: false,
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
})
}
componentDidMount() {
this.loadCommentsFromServer();
setInterval(this.loadCommentsFromServer, this.props.pollInterval);
}
render() {
let url="/public/comments.json"
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList data={this.state.data} />
<CommentForm />
</div>
);
}
}
class CommentList extends React.Component {
render() {
let data = this.props.data
var commentNodes = data.map(function (comment) {
return (
<Comment author={comment.author}>
{comment.text}
</Comment>
);
});
return (
<div className="commentList">
{commentNodes}
</div>
);
}
};
class Comment extends React.Component {
render() {
return(
<div className="comment">
<h2 className="commentAuthor">
{this.props.author}
</h2>
{this.props.children}
</div>
);
}
}
class CommentForm extends React.Component {
render() {
return (
<div className="commentForm">
Hello, world! I am a CommentForm.
</div>
);
}
};
export default CommentBox;
However, the tutorial is a bit outdated and I am using React 0.14-rc1 with ES6 syntax. I have tried my best to follow the tutorial and implementing it the 0.14 way. Was able to get to this point but now getting the error:
TypeError: this.props is undefined
Could not figure out the issue. Any idea why? Thanks
Upvotes: 29
Views: 58874
Reputation: 441
I am also new to React and one thing is worth to notice while working with state and props inside function is USE FUNCTION VARIABLE ie.
func(){this.setState}
result error
func=()=>{this.setState}
will work
same is the case with
this.props
inside function
Note even you are not using function.bind(this) with its context inside constructor.
Upvotes: 0
Reputation: 33974
The ajax code can be improved like below using arrow function to avoid scope issues and to access props inside
loadCommentsFromServer = () => {
$.ajax({
url: this.props.url,
dataType: 'json',
cache: false,
success: (data) => {
this.setState({data: data});
},
error: (xhr, status, err) => {
console.error(this.props.url, status, err.toString());
}
})
}
Upvotes: 1
Reputation: 87
Passing the props
to the constructor will help:
constructor(props) {
super(props);
}
Upvotes: 8
Reputation: 53
Although all of the above answers are technically correct, they did not work in my case. I received some crazy error 'Missing class properties transform' so rather than trying to figure that out I defined the handler right in the event like so:
export class ComponentClass extends React.Component{
_myHandler(event) {
event.preventDefault();
console.log(this.props.thingIPassedIn);
}
render() {
return <Button onClick={(event) => this._myHandler(event)} type="button" className="btn btn-danger">Click Me!</Button>;
}
}
You can also pass parameters this way.
export class ComponentClass extends React.Component{
_myHandler(thingIPassedIn) {
console.log(thingIPassedIn);
}
render() {
return <MyOtherComponent defNotAnEvent={(thingIPassedIn) => this._myHandler(thingIPassedIn)} />;
}
}
Upvotes: 1
Reputation: 16660
With the shift of React from createClass to ES6 classes
we need to handle the correct value of this
to our methods on our own, as mentioned here: http://www.newmediacampaigns.com/blog/refactoring-react-components-to-es6-classes
Change your code to have the method bounded to correct value of this in consructor:
export default class ComponentClass extends React.Component {
constructor(props) {
super(props);
this._myHandler = this._myHandler.bind(this);
}
_myHandler(props) {
console.log(props);
}
render() {
return (
<div className="col-xs-6 col-md-4">
<button type="button" className="btn btn-danger" onClick={this._myHandler}><i className="fa fa-trash"> Delete</i></button>
</div>
)
}
}
The no autobinding
was a deliberate step from React guys for ES6 classes. Autobinding to correct context was provided with React.createClass
. Details of this can be found here: https://facebook.github.io/react/blog/2015/01/27/react-v0.13.0-beta-1.html#autobinding
So based on this you could also change your code as:
export default class ComponentClass extends React.Component {
_myHandler = (props) => {
console.log(props);
}
render() {
return (
<div className="col-xs-6 col-md-4">
<button type="button" className="btn btn-danger" onClick={this._myHandler}><i className="fa fa-trash"> Delete</i></button>
</div>
)
}
}
Upvotes: 11
Reputation: 47172
When using React and ES6 classes React won't auto bind functions that is declared on your class.
Therefore either use this.loadCommentsFromServer.bind(this)
or use arrow functions
loadCommentsFromServer = () => {}
Upvotes: 45