Reputation: 161
I think I'm having a fundamental issue understanding state and props... I have an array of records, and when I console.log the array it returns the correct records, but .setState is not changing the returned records in the UI. I wonder if perhaps handleCommentDelete needs to be moved to the parent component? Here's the parent:
import React from 'react';
import { render } from 'react-dom';
import CommentForm from './CommentForm';
import CommentList from './CommentList';
class CommentBox extends React.Component {
constructor(props) {
super(props);
this.state = { data: [] };
this.handleCommentSubmit = this.handleCommentSubmit.bind(this);
}
componentDidMount() {
this.loadCommentsFromServer();
window.setInterval(
() => this.loadCommentsFromServer(),
this.props.pollInterval,
);
}
handleCommentSubmit(comment) {
const comments = this.state.data;
comment.Id = comments.length + 1;
const newComments = comments.concat([comment]);
this.setState({ data: newComments });
const data = new FormData();
data.append('Id', comment.Id);
data.append('Name', comment.Name);
data.append('Phone', comment.Phone);
data.append('Email', comment.Email);
const xhr = new XMLHttpRequest();
xhr.open('post', this.props.submitUrl, true);
xhr.onload = () => this.loadCommentsFromServer();
xhr.send(data);
}
loadCommentsFromServer() {
const xhr = new XMLHttpRequest();
xhr.open('get', this.props.url, true);
xhr.onload = () => {
const data = JSON.parse(xhr.responseText);
this.setState({ data: data });
};
xhr.send();
}
render() {
return (
<div className="row padBottom_10">
<div className="col-md-12">
<CommentForm onCommentSubmit={this.handleCommentSubmit} />
</div>
<div className="col-md-12">
<div className="commentBox border borderBorderGrey highlightPrimaryGrey">
<CommentList data={this.state.data} />
</div>
</div>
</div>
);
}
}
export default CommentBox;
...and here's the child component, where I'm trying to delete a record.
import React from 'react';
import { render } from 'react-dom';
class CommentList extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [{}]
};
this.handleCommentDelete = this.handleCommentDelete.bind(this);
}
handleCommentDelete(id) {
console.log(this.props.data); // returns n records
let comments = [...this.props.data];
this.setState({
data: comments.filter(comment => comment.Id !== id)
});
console.log(comments.filter(comment => comment.Id !== id)); // returns n - 1 records
}
render() {
return (
<table className="commentList react-bs-table">
<thead>
<tr>
<th>Name</th>
<th>Phone</th>
<th>Email</th>
<th></th>
</tr>
</thead>
<tbody>
{
this.props.data.map((comment, i) => {
return (
<tr className="comment" key={i}>
<td className="commentId">{comment.Id}</td>
<td className="commentName">{comment.Name}</td>
<td className="commentPhone">{comment.Phone}</td>
<td className="commentEmail">{comment.Email}</td>
<td className="commentCRUD">
<a onClick={() => this.handleCommentDelete(comment.Id)}>
<i className="fa fa-trash" />
</a>
</td>
</tr>
);
})
}
</tbody>
</table>
);
}
}
export default CommentList;
I'm really beating my head against the wall to understand this... thanks in advance for any help!
Upvotes: 0
Views: 99
Reputation: 539
handleCommentDelete
should be in the parent component. You can pass the function down to the child from the parent as a prop.
Pass a function to a child component
<CommentList data={this.state.data} handleCommentDelete={this.handleCommentDelete} />
Parent function
handleCommentDelete = (id) => {
this.setState({
data: this.state.data.filter(comment => comment.Id !== id)
});
}
Reference prop function
<a onClick={() => this.props.handleCommentDelete(comment.Id)}>
You are mixing state and props in the child when it should just be props. Pass handleCommentDelete
as a prop to the child, call it with this.props.handleCommentDelete(id)
, and update the state in the parent to reflect the delete. This will then rerender the child with the new list of comments.
Upvotes: 1