关于我的表格状态应该存在的地方我处于两难境地。
React Docs提到:
根据该状态识别呈现某些内容的每个组件。查找公共所有者组件(在层次结构中需要状态的所有组件上方的单个组件)。公共所有者或层次结构中较高层的其他组件应该拥有该状态。如果找不到拥有状态的组件,只需创建一个新组件来保存状态,并将其添加到公共所有者组件上方的层次结构中的某个位置。
我有一个简单的评论UI。
组件Highrarchy如下:
- CommentSection.jsx ---> main (should "Post" state (?))
-comment-post.jsx ---> User Comment Form
- comment-table.jsx
- comment.jsx
- comment-avatar.jsx
- comment-body.jsx
问题:在comment-post.jsx
中,input和textarea字段具有onChange()事件处理程序,并且在提交帖子按钮上还有一个单击事件句柄。我可以选择做两个中的一个:
comment-post.jsx
中,当onChange触发时,将commentBody发送到CommentSection.jsx
这里的问题是我将在用户输入后立即发送commentBody,然后在触发时发送名称,依此类推comment-post.jsx
中,当onChange触发SAVE状态值时,然后在状态中命名名称字段,当用户单击提交按钮发送到CommentSection.jsx
时,好处是字段在状态中首先设置,当用户点击发布时,它们被发送到父级(因为它应该是对的?)是否应将注释的输入字段(即commentBody和Name)保存在
comment-post.jsx
(表单组件)或父组件中?
现在我正在做的状态2.在状态中保存表单字段,然后在提交时发送状态值。
我认为问题是onChange和onClick是两个不同的处理程序,问题是哪个应该理想地将值传递给父组件?
class CommentSection extends Component {
state = {
posts: []
};
handleCommentPost = post => {
const posts = this.state.posts;
posts.push(post);
this.setState({ posts });
};
render() {
console.log("comment:", this.state.posts);
return (
<React.Fragment>
<h1>comments</h1>
<div className="row bootstrap snippets">
<div className="col-md-6 col-md-offset-2 col-sm-12">
<div className="comment-wrapper">
<Comment_Post onClick={this.handleCommentPost} />
<Comment_Table comments={this.state.posts} />
</div>
</div>
</div>
</React.Fragment>
);
}
}
class Comment_Table extends Component {
render() {
const posts = this.props.comments;
let count = 0;
return (
<div className="panel panel-info">
<hr />
<ul className="media-list">
{posts.map(post => (
<Comment key={count++} comment={post.commentBody} />
))}
</ul>
</div>
);
}
}
class Comment extends Component {
render() {
return (
<li className="media">
<Comment_Avatar userAvatar={this.props.commentAvatar} />
<Comment_Body userComment={this.props.comment} />
</li>
);
}
}
class Comment_Body extends Component {
render() {
const { userComment } = this.props;
return (
<div className="media-body">
<span className="text-muted pull-right">
<small className="text-muted">30 min ago</small>
</span>
<strong className="text-success">@MartinoMont</strong>
<p>
{userComment}
{}
</p>
</div>
);
}
}
class Comment_Post extends Component {
state = {
commentBody: null
};
onCommentChange = e => {
this.setState({ commentBody: e.target.value });
};
onCommentPost = e => {
const commentBody = this.state.commentBody;
if (commentBody !== null) {
this.props.onClick({ commentBody });
}
};
onNameInput = e => {};
onCommentPostError() {}
render() {
return (
<React.Fragment>
<div className="panel-heading p-heading">Comment panel</div>
<div className="panel-body">
<textarea
onChange={this.onCommentChange}
className="form-control"
placeholder="write a comment..."
rows="3"
/>
<label htmlFor="fname" onChange={this.onNameInput}>
Name:{" "}
</label>
<input id="fname" placeholder="John" />
<br />
<button
type="button"
className="btn btn-info pull-right"
onClick={this.onCommentPost}
>
Post
</button>
<div className="clearfix" />
</div>
</React.Fragment>
);
}
}
class Comment_Avatar extends Component {
render() {
return (
<a href="#" className="pull-left">
<img
src="https://bootdey.com/img/Content/user_1.jpg"
alt=""
className="img-circle"
/>
</a>
);
}
}
我认为问题是onChange和onClick是两个不同的处理程序,问题是哪个应该理想地将值传递给父组件?
我们在标准用户界面设计中使用了两种类型的表单。首先是输入中的任何更改保存更改。其次,在更改表单元素后,按下提交按钮,然后保存更改。
由于你已经实现了第二种类型,你的onChange
应该处理控制你的TextArea状态,你的onClick
应该处理提交。所以你的代码很好。
关于我的表格状态应该存在的地方我处于两难境地。
这取决于...在您的情况下,您只有一个表单和两个表单元素,其中任何一个都不可重用。所以这些不受控制的形式对你有用。但是,如果您希望有一个可重复使用的表单组件,或者如果您想要一个包含15个字段的表单,则不希望为每个表单编写单独的onChange处理程序。为此,您需要创建一个可以为您处理所有这些事情的受控表单组件。这是一个看起来像什么的例子。
export default class Form extends React.Component {
constructor(props) {
super(props);
this.state = {
values: {}
};
}
@boundMethod
handleSubmit(event) {
event.preventDefault();
this.props.submit(this.state.values);
}
@boundMethod
handleChange(event) {
const { name, value } = event.target;
const newValues = Object.assign(
{ ...this.state.values },
{ [name]: value }
);
this.setState({
values: newValues
});
}
public render() {
const { values } = this.state;
return (
<form onSubmit={this.handleSubmit} noValidate={true}>
<div>
{React.Children.map(
this.props.children,
child => (
{React.cloneElement(child, {
value: values[child.props.name],
onChange: this.handleChange
})}
)
)}
<div>
<button type="submit">
Submit
</button>
</div>
</div>
</form>
);
}
}
然后你就可以像这样使用这个Form类:
<Form
submit={values => {
/* work with values */
}}
>
<input type="hidden" name="name" />
<input type="hidden" name="rating" />
</Form>;