第一个react.js程序:create and show comment
import React, { Component } from "react"; import { render } from "react-dom"; import PropTypes from "prop-types"; const node = document.getElementById("root"); const data = { post: { id: 123, content: "What we hope ever to do with ease, we must first learn to do with diligence. — Samuel Johnson", user: "Mark Thomas" }, comments: [ { id: 0, user: "David", content: "such. win." }, { id: 1, user: "Haley", content: "Love it." }, { id: 2, user: "Peter", content: "Who was Samuel Johnson?" }, { id: 3, user: "Mitchell", content: "@Peter get off Letters and do your homework" }, { id: 4, user: "Peter", content: "@mitchell ok :P" } ] }; class Post extends Component { constructor(props) { super(props); } render() { return React.createElement( "div", { className: "post" }, React.createElement( "h2", { className: "postAuthor", id: this.props.id }, this.props.user, React.createElement( "span", { className: "postBody" }, this.props.content ), this.props.children ) ); } } Post.propTypes = { user: PropTypes.string.isRequired, content: PropTypes.string.isRequired, id: PropTypes.number.isRequired }; class Comment extends Component { constructor(props) { super(props); } render() { return React.createElement( "div", { className: "comment" }, React.createElement( "h2", { className: "commentAuthor" }, this.props.user, React.createElement( "span", { className: "commentContent" }, this.props.content ) ) ); } } Comment.propTypes = { id: PropTypes.number.isRequired, content: PropTypes.string.isRequired, user: PropTypes.string.isRequired }; class CreateComment extends Component { constructor(props) { super(props); this.state = { content: "", user: "" }; this.handleUserChange = this.handleUserChange.bind(this); this.handleTextChange = this.handleTextChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleUserChange(event) { const val = event.target.value; this.setState(() => ({ user: val })); } handleTextChange(event) { const val = event.target.value; this.setState({ content: val }); } handleSubmit(event) { event.preventDefault(); this.props.onCommentSubmit({ user: this.state.user.trim(), content: this.state.content.trim() }); this.setState(() => ({ user: "", content: "" })); } render() { return React.createElement( "form", { className: "createComment", onSubmit: this.handleSubmit }, React.createElement("input", { type: "text", placeholder: "Your name", value: this.state.user, onChange: this.handleUserChange }), React.createElement("input", { type: "text", placeholder: "Thoughts?", value: this.state.content, onChange: this.handleTextChange }), React.createElement("input", { type: "submit", value: "Post" }) ); } } CreateComment.propTypes = { onCommentSubmit: PropTypes.func.isRequired, content: PropTypes.string }; class CommentBox extends Component { constructor(props) { super(props); this.state = { comments: this.props.comments }; this.handleCommentSubmit = this.handleCommentSubmit.bind(this); } handleCommentSubmit(comment) { const comments = this.state.comments; comment.id = Date.now(); const newComments = comments.concat([comment]); this.setState({ comments: newComments }); } render() { return React.createElement( "div", { className: "commentBox" }, React.createElement(Post, { id: this.props.post.id, content: this.props.post.content, user: this.props.post.user }), this.state.comments.map(function(comment) { return React.createElement(Comment, { key: comment.id, id: comment.id, content: comment.content, user: comment.user }); }), React.createElement(CreateComment, { onCommentSubmit: this.handleCommentSubmit }) ); } } CommentBox.propTypes = { post: PropTypes.object, comments: PropTypes.arrayOf(PropTypes.object) }; render( React.createElement(CommentBox, { comments: data.comments, post: data.post }), node );
在线code:https://codesandbox.io/s/z6o64oljn4?file=/index.js:0-4834
摘抄自:Minning React In Action 书中 P52页
- Post的component比较简单,就是现实文章post内容。Comment组件也是简单的现实comment内容。两个组件都不涉及state数据。
- CreateComment组件包括了用户输入评论内容部分,有一个state:包含用户名和内容的数据,其中点击了submit按钮后,就调用函数:handleSubmit,而这个函数其实是调用了通过prop传过来的父组件prop中的onCommentSubmit函数,这样就把本组件中的state数据传给父组件了。
- CommentBox 是个复合组件,其child包括了post,多个comment和一个CreateComment组件。它的state是comment组件的数组comments,又定义了handleCommentSubmit函数,该函数通过给CreateComment组件的prop中给了子组件,handleCommentSubmit的作用是把从CreateComment组件搜集到的数据添加到自己state中的comments数组中,而其child组件中用到了.map()函数来把state中的comments数组组成一个Comment组件数组。
- render方法最后只render渲染CommentBox组件。
其中关于code中的.bind()函数,对于JS新手来说比较迷惑,如果缺少了这个程序就不工作了。关于bind方法 see: https://www.javascripttutorial.net/javascript-bind/#:~:text=The%20bind%20%28%29%20method%20creates%20a%20new%20function%2C,This%20is%20known%20as%20function%20borrowing%20in%20JavaScript.
https://www.w3schools.com/js/js_function_bind.asp
下面是用JSX写的同一程序:https://codesandbox.io/s/vnwz6y28x5?file=/index.js
import React, { Component } from "react"; import { render } from "react-dom"; import PropTypes from "prop-types"; const node = document.getElementById("root"); const data = { post: { id: 123, content: "What we hope ever to do with ease, we must first learn to do with diligence. — Samuel Johnson", user: "Mark Thomas" }, comments: [ { id: 0, user: "David", content: "such. win." }, { id: 1, user: "Haley", content: "Love it." }, { id: 2, user: "Peter", content: "Who was Samuel Johnson?" }, { id: 3, user: "Mitchell", content: "@Peter get off Letters and do your homework" }, { id: 4, user: "Peter", content: "@mitchell ok :P" } ] }; class Post extends Component { render() { return ( <div className="post"> <h2 className="postAuthor">{this.props.user}</h2> <span className="postBody">{this.props.content}</span> {this.props.children} </div> ); } } Post.propTypes = { user: PropTypes.string.isRequired, content: PropTypes.string.isRequired, id: PropTypes.number.isRequired }; class Comment extends Component { render() { return ( <div className="comment"> <h2 className="commentAuthor">{this.props.user + " : "}</h2> <span className="commentContent">{this.props.content}</span> </div> ); } } Comment.propTypes = { id: PropTypes.number.isRequired, content: PropTypes.string.isRequired, user: PropTypes.string.isRequired }; class CreateComment extends Component { constructor(props) { super(props); this.state = { content: "", user: "" }; this.handleUserChange = this.handleUserChange.bind(this); this.handleTextChange = this.handleTextChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleUserChange(event) { this.setState({ user: event.target.value }); } handleTextChange(event) { this.setState({ content: event.target.value }); } handleSubmit(event) { event.preventDefault(); this.props.onCommentSubmit({ user: this.state.user.trim(), content: this.state.content.trim() }); this.setState({ user: "", content: "" }); } render() { return ( <form onSubmit={this.handleSubmit} className="createComment"> <input value={this.state.user} onChange={this.handleUserChange} placeholder="Your name" type="text" /> <input value={this.state.content} onChange={this.handleTextChange} placeholder="Thoughts?" type="text" /> <button type="submit">Post</button> </form> ); } } class CommentBox extends Component { constructor(props) { super(props); this.state = { comments: this.props.comments }; this.handleCommentSubmit = this.handleCommentSubmit.bind(this); } handleCommentSubmit(comment) { const comments = this.state.comments; comment.id = Date.now(); const newComments = comments.concat([comment]); this.setState({ comments: newComments }); } render() { return ( <div className="commentBox"> <Post id={this.props.post.id} content={this.props.post.content} user={this.props.post.user} /> {this.state.comments.map(function(comment) { return ( <Comment key={comment.id} content={comment.content} user={comment.user} /> ); })} <CreateComment onCommentSubmit={this.handleCommentSubmit} /> </div> ); } } CommentBox.propTypes = { post: PropTypes.object, comments: PropTypes.arrayOf(PropTypes.object) }; render(<CommentBox comments={data.comments} post={data.post} />, node);