React.js 小书 Lesson25 - 实战分析:评论功能(四)
- 作者:胡子大哈
- 原文链接:http://huziketang.com/books/react/lesson25
- 转载请注明出处,保留原文链接和作者信息。
(本文未审核)
目前为止,第二阶段知识已经基本介绍完,我们已经具备了项目上手实战必备的 React.js 知识,现在可以把这些知识应用起来。接下来是实战环节,我们会继续上一阶段的例子,把评论功能做得更加复杂一点。
我们在上一阶段的评论功能基础上加上以下功能需求:
- 页面加载完成自动聚焦到评论输入框。
- 把用户名持久化,存放到浏览器的 LocalStorage 中。页面加载时会把用户名加载出来显示到输入框,用户就不需要重新输入用户名了。
- 把已经发布的评论持久化,存放到浏览器的 LocalStorage 中。页面加载时会把已经保存的评论加载出来,显示到页面的评论列表上。
- 评论显示发布日期,如“1 秒前”,”30 分钟前”,并且会每隔 5 秒更新发布日期。
- 评论可以被删除。
- 类似 Markdown 的行内代码块显示功能,用户输入的用 `` 包含起来的内容都会被处理成用
<code>元素包含。例如输入 `console.log` 就会处理成<code>console.log</code>再显示到页面上。

大家可以在原来的第一阶段代码的基础上进行修改,第一、二阶段评论功能代码可以在这里找到: react-naive-book-examples。可以直接使用最新的样式文件 index.css 覆盖原来的 index.css。
接下来可以分析如何利用第二阶段的知识来构建这些功能,在这个过程里面可能会穿插一些小技巧,希望对大家有用。我们回顾一下这个页面的组成:

我们之前把页面分成了四种不同的组件:分别是 CommentApp 、CommentInput、CommentList、Comment。我们开始修改这个组件,把上面的需求逐个完成。
自动聚焦到评论框
这个功能是很简单的,我们需要获取 textarea 的 DOM 元素然后调用 focus() API 就可以了。我们给输入框元素加上 ref 以便获取到 DOM 元素,修改 src/CommentInput.js 文件:
...
<textarea
ref={(textarea) => this.textarea = textarea}
value={this.state.content}
onChange={this.handleContentChange.bind(this)} />
...
组件挂载完以后完成以后就可以调用 this.textarea.focus(),给 CommentInput 组件加上 ComponentDidMount 生命周期:
class CommentInput extends Component {
static propTypes = {
onSubmit: PropTypes.func
}
constructor () {
super()
this.state = {
username: '',
content: ''
}
}
componentDidMount () {
this.textarea.focus()
}
...
这个功能就完成了。现在体验还不是很好,接下来我们把用户名持久化一下,体验就会好很多。
大家可以注意到我们给原来的 props.onSubmit 参数加了组件参数验证,在这次实战案例中,我们都会给评论功能的组件加上 propTypes 进行参数验证,接下来就不累述。
持久化用户名
用户输入用户名,然后我们把用户名保存到浏览器的 LocalStorage 当中,当页面加载的时候再从 LocalStorage 把之前保存的用户名显示到用户名输入框当中。这样用户就不用每次都输入用户名了,并且评论框是自动聚焦的,用户的输入体验就好很多。
我们监听用户名输入框失去焦点的事件 onBlur:
...
<input
value={this.state.username}
onBlur={this.handleUsernameBlur.bind(this)}
onChange={this.handleUsernameChange.bind(this)} />
...
在 handleUsernameBlur 中我们把用户的输入内容保存到 LocalStorage 当中:
class CommentInput extends Component {
constructor () {
super()
this.state = {
username: '',
content: ''
}
}
componentDidMount () {
this.textarea.focus()
}
_saveUsername (username) {
localStorage.setItem('username', username)
}
handleUsernameBlur (event) {
this._saveUsername(event.target.value)
}
...
在 handleUsernameBlur 中我们把用户输入的内容传给了 _saveUsername 私有方法(所有私有方法都以 _ 开头)。_saveUsername 会设置 LocalStorage 中的 username 字段,用户名就持久化了。这样就相当于每当用户输入完用户名以后(输入框失去焦点的时候),都会把用户名自动保存一次。
输入用户名,然后到浏览器里里面看看是否保存了:

然后我们组件挂载的时候把用户名加载出来。这是一种数据加载操作,我们说过,不依赖 DOM 操作的组件启动的操作都可以放在 componentWillMount 中进行,所以给 CommentInput 添加 componentWillMount 的组件生命周期:
...
componentWillMount () {
this._loadUsername()
}
_loadUsername () {
const username = localStorage.getItem('username')
if (username) {
this.setState({ username })
}
}
_saveUsername (username) {
localStorage.setItem('username', username)
}
...
componentWillMount 会调用 _loadUsername 私有方法,_loadUsername 会从 LocalStorage 加载用户名并且 setState 到组件的 state.username 中。那么组件在渲染的时候(render 方法)挂载的时候就可以用上用户名了。
这样体验就好多了,刷新页面,不需要输入用户名,并且自动聚焦到了输入框。我们 1、 2 需求都已经完成。
小贴士
这里插入一些小贴示,大家可以注意到我们组件的命名和方法的摆放顺序其实有一定的讲究,这里可以简单分享一下个人的习惯,仅供参考。
组件的私有方法都用 _ 开头,所有事件监听的方法都用 handle 开头。把事件监听方法传给组件的时候,属性名用 on 开头。例如:
<CommentInput
onSubmit={this.handleSubmitComment.bind(this)} />
这样统一规范处理事件命名会给我们带来语义化组件的好处,监听(on)CommentInput 的 Submit 事件,并且交给 this 去处理(handle)。这种规范在多人协作的时候也会非常方便。
另外,组件的内容编写顺序如下:
- static 开头的类属性,如
defaultProps、propTypes。 - 构造函数,
constructor。 - getter/setter(还不了解的同学可以暂时忽略)。
- 组件生命周期。
_开头的私有方法。- 事件监听方法,
handle*。 render*开头的方法,有时候render()方法里面的内容会分开到不同函数里面进行,这些函数都以render*开头。render()方法。
如果所有的组件都按这种顺序来编写,那么维护起来就会方便很多,多人协作的时候别人理解代码也会一目了然。
因为第三方评论工具有问题,对本章节有任何疑问的朋友可以移步到 React.js 小书的论坛 发帖,我会回答大家的疑问。
React.js 小书 Lesson25 - 实战分析:评论功能(四)的更多相关文章
- React.js 小书 Lesson16 - 实战分析:评论功能(三)
作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson16 转载请注明出处,保留原文链接和作者信息. 接下来的代码比较顺理成章了.修改 Commen ...
- React.js 小书 Lesson14 - 实战分析:评论功能(一)
作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson14 转载请注明出处,保留原文链接和作者信息. 课程到这里大家已经掌握了 React.js 的 ...
- React.js 小书 Lesson26 - 实战分析:评论功能(五)
作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson26 转载请注明出处,保留原文链接和作者信息. (本文未审核) 持久化评论 同样地,可以通过类 ...
- React.js 小书 Lesson15 - 实战分析:评论功能(二)
作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson15 转载请注明出处,保留原文链接和作者信息. 上一节我们构建了基本的代码框架,现在开始完善其 ...
- React.js 小书 Lesson27 - 实战分析:评论功能(六)
作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson27 转载请注明出处,保留原文链接和作者信息. (本文未审核) 删除评论 现在发布评论,评论不 ...
- 【React.js小书】动手实现 React-redux(五):Provider - 方志
我们要把 context 相关的代码从所有业务组件中清除出去,现在的代码里面还有一个地方是被污染的.那就是 src/index.js 里面的 Index: 1234567891011121314151 ...
- React.js 小书介绍
React.js 小书 Github 关于作者 这是一本关于 React.js 的小书. 因为工作中一直在使用 React.js,也一直以来想总结一下自己关于 React.js 的一些知识.经验.于是 ...
- React.js 小书 Lesson20 - 更新阶段的组件生命周期
作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson20 转载请注明出处,保留原文链接和作者信息. 从之前的章节我们了解到,组件的挂载指的是将组件 ...
- React.js 小书 Lesson24 - PropTypes 和组件参数验证
作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson24 转载请注明出处,保留原文链接和作者信息. 我们来了到了一个非常尴尬的章节,很多初学的朋友 ...
随机推荐
- scvmm2008 错误 2921 0x8007054F
这个错误是由于bits智能传输服务依赖的https 443端口被占用.443端口一般常用于银行.购物网站,是一种加密的http,一般是通过ssl安全套接字来加密的,但是ssl漏洞可能被木马病毒利用. ...
- Echart自定义y轴刻度信息1
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- jQuery引入公共库问题
话说脚本最好放到底部,这样页面既可以逐步呈现,也可以提高下载,但是某些公共模块且有js效果,顺序优先公共库的话,效果是出不来的,所以以后就把公共库最好放在头部,(就是这个而已:http://apps. ...
- java 优秀文章集锦
一个简易的静态网页服务器 https://www.cnblogs.com/longfurcat/p/10355514.html 浅析Servlet执行原理 https://www.cnblo ...
- 利用Python工具进行打包功能
基于Python脚本 iOS 工程的自动打包 导入的库 import os import requests import webbrowser import subprocess import shu ...
- 题目1010:A + B(字符串拆分)
问题来源 http://ac.jobdu.com/problem.php?pid=1010 问题描述 给我们一行标准的字符串,整行读入之后,把它拆开转换成数字进行计算. 问题分析 首先考虑一个问题:如 ...
- 吃奶酪 状压dp
题目描述 房间里放着n块奶酪.一只小老鼠要把它们都吃掉,问至少要跑多少距离?老鼠一开始在(0,0)点处. 输入输出格式 输入格式: 第一行一个数n (n<=15) 接下来每行2个实数,表示第i块 ...
- 吴裕雄 python 机器学习——K均值聚类KMeans模型
import numpy as np import matplotlib.pyplot as plt from sklearn import cluster from sklearn.metrics ...
- Codeforces Round #556 题解
Codeforces Round #556 题解 Div.2 A Stock Arbitraging 傻逼题 Div.2 B Tiling Challenge 傻逼题 Div.1 A Prefix S ...
- css属性详解和浮动
一.CSS属性组成和作用 属性:属性值 1)每个css样式都必须由两部分组成:选择符和声明 注:声明又包括属性和属性值 2)css属性:属性是指定选择符具有的属性,他是css的核心,css2共有150 ...