学习 React 写的小练习

之前学习 ReactRedux的时候,随手做的一个小练习,一个简单的评论系统,很简陋,学习练手。边学边做,过程中容易有根据具体深刻的体会,more practise, more gain。😺

项目结构:

image-20191106160230662

效果截图:

image-20191106160316456

点击预览

主要代码:

Comment.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import React,{ Component } from 'react';
import './Comment.css'
import PropTypes from 'prop-types'


class Comment extends Component{
constructor(){
super();
this.state={
timeString:''
}
this.handleDeleteComment = this.handleDeleteComment.bind(this);
}

static propTypes = {
comment: PropTypes.object.isRequired
}

componentWillMount(){
this._updateTime()
}

_updateTime(){
console.log(this.props);
//{comment: {name: "波波", content: "我是一", createdTime: 1556527025186},key: }
const {comment} = this.props;
console.log(comment);
//{name: "波波", content: "我是一", createdTime: 1556527025186}
// console.log(typeof comment.createdTime); //number
const duration = (Date.now() - comment.createdTime) / 1000;
// console.log(duration);
this.setState({
timeString: duration > 60
? `${Math.round(duration / 60)} 分钟前`
: `${Math.round(Math.max(duration, 1))} 秒前`
})
}

handleDeleteComment(e){
if (this.props.onDeleteComment) {
console.log(this.props.index)
this.props.onDeleteComment(this.props.index)
}
}

render(){
const {comment}=this.props;
return(
<div className="comment-list">
<div className="comment-user">
<span>{comment.name}:</span>
</div>
<p>{comment.content}</p>
<span className='comment-createdtime'>{this.state.timeString}</span>
<span className='comment-delete'
onClick={this.handleDeleteComment}
>删除该条评论</span>
</div>
)
}
}

CommentApp.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import React,{ Component } from 'react';
import CommentInput from './CommentInput';
import CommentList from './CommentList'

class CommentApp extends Component{
constructor(){
super();
this.state={
comments:[],
};
this.commentUpdate = this.commentUpdate.bind(this);
this.handleDelete = this.handleDelete.bind(this);
}

componentWillMount(){
this._loadComments()
}

_loadComments(){
var comments = localStorage.getItem('comments');
if(comments){
this.setState(function () {
return{
comments: JSON.parse(comments)
}
})
}else{
this.setState(function () {
return{
comments:this.state.comments
}
})
}
}

_updateComments(comments){
localStorage.setItem('comments',JSON.stringify(comments))
}

commentUpdate(comment){
// 不能直接操作this.state中的属性的属性值,包括赋值和数组的加减操作,
// 可以赋值给一个新变量,再将新变量通过setState给到this.state中的属性,
// 从而实现数据变化,并重新渲染
// 方法一:
if(!comment) return;
if(!comment.name) alert('请输入用户名');
if(!comment.content) alert('请输入评论内容');

const comments = this.state.comments;

comments.push(comment);
this.setState(()=>{
return{
comments:comments
}
});

this._updateComments(comments)
// 方法二:剩余参数
// this.setState(()=>({comments: [...this.state.comments,comment]}));

// 方法三:setState函数参数
// this.setState((prevState,props)=>{
// // 固定参数,第一个是this.state的前一个状态;第二个参数为属性对象props
// console.log(prevState)
// console.log(comment)
// console.log(props); //{}
//
// return{
// comments:[...prevState.comments,comment]
// }
// })
}

handleDelete(index){
const comments = this.state.comments;
comments.splice(index,1);
this.setState(function () {
return{
comments:comments
}
});
this._updateComments(comments)
}

render(){
return(
<div className="wrapper">
{/*作为组件调用时可以有属性和方法,使用上和标签相同,可通过给组件加属性和方法实现向组件间的数据传递*/}
<CommentInput updateComment={this.commentUpdate}/>
<CommentList comments={this.state.comments}
onDeleteComment={this.handleDelete}/>
</div>
)
}
}

CommentInput.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import React,{ Component } from 'react';
import './CommentInput.css'

class CommentInput extends Component{
constructor(){
super();
this.state = {
name:'',
content:''
};
this.handleUsernameChange = this.handleUsernameChange.bind(this);
this.handleCommentChange = this.handleCommentChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleUsernameBlur = this.handleUsernameBlur.bind(this);
}

componentWillMount(){
// 在render之前执行
this._loadUsername()
}

componentDidMount(){
//在render之后执行
this.textarea.focus();

}

// 持久化用户名:将用户名保存到localStorage
_saveUsername(username){
localStorage.setItem('username',username)
}

// 页面刷新时加载用户名
_loadUsername(){
var username = localStorage.getItem('username');
if(username){
this.setState(()=>{
return{
name:username
}
})
}
}

handleUsernameChange(e){
const name = e.target.value;
// 对于事件处理函数的event对象,setState的参数函数不识别,只能放在外面

this.setState(function (prevState) {
return{
name:name
// 这里可以简写为{name}
}
})
}

handleCommentChange(e){
const content = e.target.value;

this.setState(function (prevState) {
return{
content:content
}
})
}

handleSubmit(){
// 向父组件传递数据,在子组件调用父组件的方法,将要传递的数据作为方法的参数
this.props.updateComment(
{
name: this.state.name,
content: this.state.content,
createdTime: Date.now()
});

// 提交数据完成后,清空内容区,保留用户名
this.setState(()=>{
return{
content:''
}
})
}

handleUsernameBlur(event){
// 输入框失去焦点时,将值保存都localStorage中
this._saveUsername(event.target.value)
}

handleCommentBlur(event){
this._saveComment(event.target.value)
}

render(){
return(
<div className="comment-input">
<div className="comment-field">
<span className="comment-field-name">用户名:</span>
<div className="comment-field-input">
<input type="text"
value={this.state.name}
onChange={this.handleUsernameChange}
onBlur={this.handleUsernameBlur}
/>
</div>
</div>
<div className="comment-field">
<span className="comment-field-name">评论内容:</span>
<div className="comment-field-input">
<textarea value={this.state.content}
onChange={this.handleCommentChange}
ref={(textarea)=>this.textarea=textarea}
/>
</div>
</div>
<div className="comment-field-button">
<button onClick={this.handleSubmit}
>发布</button>
</div>
</div>
)
}
}

CommentList.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import React,{ Component } from 'react';
import Comment from './Comment'

class CommentList extends Component{

handleDelete(index){
console.log(this.props);
if(this.props.onDeleteComment){
this.props.onDeleteComment(index)
}
}

render(){
const {comments}=this.props;
// console.log(comments);
return(
<div>
{
comments.map( (comment,index)=> {
// key值要加在循环的最外层
return(
<Comment comment={comment}
key={index}
index={index}
onDeleteComment={this.handleDelete.bind(this)}
/>
)
})
}
</div>
)
}
}
0%