Reputation: 317
I am new to React and I'm trying to make a "delete button" on my Twitter-ish app for my practice. It should look just like the real Twitter, there's a list of all of my tweets and each tweet has a delete button.
I'm successfully showing all of my tweets, but I'm currently getting an error around my delete button saying Uncaught TypeError: this.props.onDelete is not a function
and I have no idea how to fix it. How can I make it to work?
My codes are as follows:
Tweet.js
import React from 'react'
class Tweet extends React.Component {
constructor(props) {
super(props);
this.state = {
tweet: this.props.tweet,
id: this.props.id,
};
this.handleDelete = this.handleDelete.bind(this);
}
handleDelete(id) {
this.props.onDelete(id);
}
render() {
const tweet = this.state.tweet;
return (
<div>
<p>{tweet.user.user_name} {tweet.created_at}</p>
<p>{tweet.tweet}</p>
<button onClick={this.handleDelete(tweet.id)}>DELETE</button>
</div>
);
}
}
export default Tweet;
Tweets.js
import React from 'react'
import Tweet from './Tweet'
class Tweets extends React.Component {
constructor(props) {
super(props);
this.state = {
tweet: this.props.tweet,
id: this.props.id,
};
}
render() {
const tweets = this.props.tweets.map(function (tweet) {
return <Tweet tweet={tweet} key={tweet.id} />;
});
return (
<div>
{tweets}
</div>
);
}
}
export default Tweets;
TweetsPage.js
import React from 'react'
import Tweets from './Tweets'
class TweetsPage extends React.Component {
constructor() {
super();
this.state = {
tweets: [],
id: '',
};
this.onSubmitDelete = this.onSubmitDelete.bind(this);
}
loadTweetsFromServer() {
const url = '/tweets/index.json';
$.ajax({
url: url,
dataType: 'json',
type: 'GET',
cache: false,
success: (data) => {
this.setState({
tweets: data
});
},
error: (xhr, status, err) => {
console.error(url, status, err.toString());
},
});
}
onSubmitDelete(id) {
const url = '/tweets/destroy';
$.ajax({
url: url,
type: 'POST',
cache: false,
data: {
id: id
},
success: (data) => {
this.loadTweetsFromServer();
},
error: (xhr, status, err) => {
console.error(url, status, err.toString());
},
});
}
componentDidMount() {
this.loadTweetsFromServer();
}
render() {
return (
<div>
<Tweets tweets={this.state.tweets} onDelete={this.onSubmitDelete} />
</div>
);
}
}
export default TweetsPage;
Upvotes: 2
Views: 1147
Reputation: 6299
You need to pass the handler to your child. Rest of your code is perfect.
TweetsPage.js - No change in this file
import React from 'react'
import Tweets from './Tweets'
class TweetsPage extends React.Component {
constructor() {
super();
this.state = {
tweets: [],
id: '',
};
this.onSubmitDelete = this.onSubmitDelete.bind(this);
}
loadTweetsFromServer() {
// load and set state
}
onSubmitDelete(id) {
// submit delete req to server
}
componentDidMount() {
this.loadTweetsFromServer();
}
render() {
return (
<div>
<Tweets tweets={this.state.tweets} onDelete={this.onSubmitDelete} />
</div>
);
}
}
export default TweetsPage;
Tweets.js - Note the changes
import React from 'react'
import Tweet from './Tweet'
class Tweets extends React.Component {
constructor(props) {
super(props);
this.state = {
tweet: this.props.tweet,
id: this.props.id,
};
}
render() {
let { onDelete, tweets } = this.props; // note this line
// note the next line - arrow function and different variable name
const renderedTweets = tweets.map((tweet) => {
// note the next line
return <Tweet tweet={tweet} key={tweet.id} onDelete={onDelete} />;
});
return (
<div>
{renderedTweets}
</div>
);
}
}
export default Tweets;
Tweet.js - No change in this file
import React from 'react'
class Tweet extends React.Component {
constructor(props) {
super(props);
this.state = {
tweet: this.props.tweet,
id: this.props.id,
};
this.handleDelete = this.handleDelete.bind(this);
}
handleDelete(id) {
this.props.onDelete(id);
}
render() {
const tweet = this.state.tweet;
return (
<div>
<p>{tweet.user.user_name} {tweet.created_at}</p>
<p>{tweet.tweet}</p>
<button onClick={this.handleDelete(tweet.id)}>DELETE</button>
</div>
);
}
}
export default Tweet;
Upvotes: 2
Reputation: 7910
You pass the onDelete
function as a prop to your Tweets component but not to your Tweet component. Your Tweet component tries to call it in the handleDelete function. To fix this, pass the prop onto the Tweet component.
render() {
let that = this
const tweets = this.props.tweets.map(function (tweet) {
return <Tweet tweet={tweet} key={tweet.id} onDelete={that.props.onDelete} />;
});
return (
<div>
{tweets}
</div>
);
}
Upvotes: 3