React Conf 2017在加利福尼亚州的圣克拉拉万豪酒店圆满落幕,这已是Facebook举办的第三届React官方大会了。
虽然不能参会,可是做为前端开发者,咱们固然不能错过这个绝佳的学习契机。javascript
笔者利用清明假期,参看了YouTube上关于此次大会的记录。一共34个精彩演讲,对应34个视频。获益匪浅。前端
这里,将会做为一个系列,对其中的几篇演讲进行翻译和分析。并辅助以code demo,帮助你们理解。java
欢迎关注个人简书或掘金帐号,也欢迎在Github上follow,最新的大会code demo,即可第一时间掌握。node
今天为你们介绍的是Ben Ilegbodu的主题:React + ES next = ♥ react
Ben Ilegbodu是“为数很少的”参会有色程序员,黑人程序员如同女性程序员同样百里挑一。可是,本次分享主题颇有爱,颇有养分,精彩程度丝绝不打折扣。若是你不了解React也没关系,由于此次讲的是ES六、ES7在React中的应用。因此,实际上是对下一代ES的普及和介绍。jquery
本文将以git
这几方面展开。并经过nodeJS实现一个兼具前端和后端的小型“评论/留言 发布阅读系统”。程序员
建议看这篇文章的同时,结合视频一块儿研究:Ben Ilegbodu - React + ES next = ♥ - React Conf 2017github
如图,咱们实现了以下的页面。这是一个前端+后端的全栈小项目。
固然,样式是极其简陋的。做为“粗糙”的程序员,实在懒得在页面上花时间。ajax
咱们能够在输入框内输入姓名和留言内容。并点击按钮提交。后台使用nodeJS express框架,实现对文件的读写更新。
app.post('/api/comments', function(req, res) {
fs.readFile(COMMENTS_FILE, function(err, data) {
if (err) {
console.error(err);
process.exit(1);
}
var comments = JSON.parse(data);
var newComment = {
id: Date.now(),
author: req.body.author,
text: req.body.text,
};
comments.push(newComment);
fs.writeFile(COMMENTS_FILE, JSON.stringify(comments, null, 4), function(err) {
if (err) {
console.error(err);
process.exit(1);
}
res.json(comments);
});
});
});复制代码
这是nodeJS的后端代码,若是不理解也不要紧。
接下来咱们继续回到演讲。
在咱们的项目中,最第一版存在这样的一段代码:
_handleCommentSubmit(comment) {
let comments = this.state.comments;
...
// remaining code
}复制代码
请务必记住这个_handleCommentSubmit函数,接下来的全文都是围绕他展开,并进行一步步拓展。
这个函数的逻辑是对新提交的comment进行处理,首先他须要从state中读取现有的comments数组。
在使用解构赋值的状况下,咱们重构为:
_handleCommentSubmit(comment) {
let {comments} = this.state;
...
// remaining code
}复制代码
也许这还看不出来解构到底有什么做用,可是在逻辑多的时候,他是颇有必要的。好比:
let author = this.state.author;
let text = this.state.text;复制代码
就能够写为:
let {author, text} = this.state;复制代码
若是须要改变变量名时,就能够从:
let authorName = this.state.author;
let fullText = this.state.text;复制代码
改成:
let {author: authorName, text: fullText} = this.state;复制代码
再举一个例子,在function component(React无状态组件编写的一种推荐形式)状况下:
function MyComponent(props) {
return (
<div style={props.style}>{props.children}</div>
)
}
<MyComponent style="dark">Stateless function!</MyComponent>复制代码
咱们能够改写为:
function MyComponent({children, style}) {
return (
<div style={style}>{children}</div>
)
}
<MyComponent style="dark">Stateless function!</MyComponent>复制代码
还记得上面那个_handleCommentSubmit函数吗?
接下来咱们要进行扩充。首先咱们将新提交的comment(即函数参数),添加一个时间戳做为id。接下来,
咱们拿到旧的state.comments以后,就要将新的comment(包含id)加入到state.comments当中。
第一版作法是:
_handleCommentSubmit(comment) {
let {comments} = this.state;
let newComment = comment;
newComment.id = Date.now();
let newComments = comments.concat([newComment]);
...
// setState + ajax stuffs
}复制代码
在使用展开符后,咱们能够重构为:
_handleCommentSubmit(comment) {
let {comments} = this.state;
let newComment = {...comment, id: Date.now()};
let newComments = [...comments, newComment];
...
// setState + ajax stuffs
}复制代码
固然,展开符还有不少其余benefits;好比,平时咱们可使用Math.max方法对数组求出最大值:
var arrayOfValue = [33, 2, 9];
var maxValueFromArray = Math.max.apply(null, arrayOfValue)复制代码
这个思路利用了apply接受一个数组做为函数参数的特性。
使用展开符,咱们就能够:
var arrayOfValue = [33, 2, 9];
var maxValueFromArray = Math.max(...arrayOfValue);复制代码
同理,咱们能够这样扩充一个数组:
let values = [2, 3, 4];
let verbose = [1, ...values, 5];复制代码
固然,以上都是对数组的展开。
对对象属性的展开符的使用,也已经到了Stage3阶段。从此,咱们能够这样写代码:
let warriors = {Steph: 95, Klay: 82, Draymond: 79};
let newWarriors = {
...warriors,
Kevin: 97
}复制代码
而没必要再使用Object.assign进行对象的扩展。
箭头函数带来的好处无疑是对this的绑定。
如今再回到咱们的_handleCommentSubmit函数。作完了初始化工做,咱们须要将新的comment经过ajax,异步发送给后端。在成功的回调函数中,进行setState处理:
$.ajax({
url: this.props.url,
data: comment,
success: function(resJson) {
this.setState({comments: resJson})
}.bind(this)
})复制代码
有经验的同窗注意到了我使用bind更改this指向的处理。
在ES6箭头函数下,咱们能够直接:
$.ajax({
url: this.props.url,
data: comment,
success: (resJson) => {
this.setState({comments: resJson})
}
})复制代码
咱们再展开看看箭头函数的几种用法(使用方式):
let squares = [1, 2, 3].map(value => value * value);复制代码
let sum = [9, 8, 7].reduce((prev, value) => prev + value, 0)复制代码
这时候,须要把参数放在括号之中。
const alertUser = (message) => {
alert(message)
}复制代码
这时候,函数体用花括号围起来。
const MyComponent = ({children, style}) => (
<div style={style}>{children}</div>
)复制代码
上面的代码咱们使用了jquery的ajax方法发送异步请求,这可能在某些状况下出现“回调地狱”的状况。为此,咱们使用基于Promise的fetch方法,进行重构:
_handleCommentSubmit(comment) {
// ...
fetch(this.props.url, {
method: 'POST',
body: Json.stringify(comment)
})
.then((res)=>res.json())
.then((resJson)=>{
this.setState({comments: resJson})
})
.catch((ex)=>{
console.error(this.props.url, ex)
})
}复制代码
固然,咱们能够把上述代码作的更抽象:
const fetchJson = (path, options) => {
fetch(`${DOMAIN}${path}`, options)
.then((res)=>res.json())
}复制代码
咱们在拉取评论时,就能够:
const fetchComments = () => fetchJson('api/comments')复制代码
基于promises的fetch,让异步请求变的灵活可靠。
同时,我再安利一个基于promises的sleep函数:
const sleep = (delay = 0) => {
new Promise((resolve)=>{
setTimeout(resolve, delay)
})
}
sleep(3000)
.then(()=>getUniqueCommentAuthors())
.then((uniqueAuthors)=>{this.state({uniqueAuthors})})复制代码
回到咱们的Project中,在后端nodeJS实现里,咱们把全部的评论存在data/comments.json文件当中。
在渲染视图时,就不可避免地要进行对data/comments.json文件读取,这个过程也应该是异步完成的:
const readFile = (filePath) => (
new Promise((resolve, reject)=>{
fs.readFile(filePath, (err, data)=>{
if (err) {reject(err)}
resolve(data)
})
})
)
readFile('data/comments.json')
.then((data)=>console.log('Here is the data', data))
.catch((ex)=>console.log('Arg!', ex))复制代码
固然,Promises实现也有缺点。
更先进的方式,就是使用Async,回到咱们的_handleCommentSubmit方法,咱们能够重构为:
async _handleCommentSubmit(comment) {
try {
let res = await fetch(this.props.url, {
method: 'POST',
body: JSON.stringify(comment)
});
newComments = await res.json();
}
catch (ex) {
console.error(this.props.url, ex);
newComments = comments;
}
this.setState({comments: newComments});
}复制代码
这篇演讲生动形象地阐释了React是怎样与ES next融合完美无缺的。不管是React也好,仍是ES也好,其实笔者认为说到底,都是为了更大限度地解放生产力。
欢迎读者与我交流,有任何问题能够留言。从此几天,将有更多新鲜的react conf视频翻译奉献给你们。
Happy Coding!
PS: 做者Github仓库,欢迎经过代码各类形式交流。