React Conf 2017在加利福尼亚州的圣克拉拉万豪酒店圆满落幕,这已经是Facebook举办的第三届React官方大会了。
虽然不能参会,但是作为前端开发者,我们当然不能错过这个绝佳的学习契机。

笔者利用清明假期,参看了YouTube上关于这次大会的记录。一共34个精彩演讲,对应34个视频。获益匪浅。

这里,将会作为一个系列,对其中的几篇演讲进行翻译和分析。并辅助以code demo,帮助大家理解。

欢迎关注我的简书掘金账号,也欢迎在Github上floow,最新的大会code demo,便可第一时间掌握。

今天为大家介绍的是Ben Ilegbodu的主题:React + ES next = ♥

Ben Ilegbodu是“为数不多的”参会有色程序员,黑人程序员如同女性程序员一样凤毛麟角。但是,本次分享主题很有爱,很有营养,精彩程度丝毫不打折扣。如果你不了解React也不要紧,因为这次讲的是ES6、ES7在React中的应用。所以,其实是对下一代ES的普及和介绍。

本文将以

  • Destructuring、
  • Spread Opetator、
  • Arrow Function、
  • Promises、
  • Async Functions

这几方面展开。并通过nodeJS实现一个兼具前端和后端的小型“评论/留言 发布阅读系统”。

建议看这篇文章的同时,结合视频一起研究:Ben Ilegbodu - React + ES next = ♥ - React Conf 2017

实现预览

如图,我们实现了如下的页面。这是一个前端+后端的全栈小项目。
当然,样式是极其简陋的。作为“粗糙”的程序员,实在懒得在页面上花时间。

es-next.png

我们可以在输入框内输入姓名和留言内容。并点击按钮提交。后台使用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的后端代码,如果不理解也没关系。

接下来我们继续回到演讲。

解构Destructuring

在我们的项目中,最初版存在这样的一段代码:

_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>

展开符Spread Opetator

还记得上面那个_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进行对象的扩展。

箭头函数Arrow Function

箭头函数带来的好处无疑是对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>
)

Promises

上面的代码我们使用了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))

Async Functions

当然,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仓库,欢迎通过代码各种形式交流。

React Conf 2017 干货总结 1: React + ES next = ♥的更多相关文章

  1. 【腾讯Bugly干货分享】React移动web极致优化

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/579083d1c9da73584b02587d 最近一个季度,我们都在为手Q家校 ...

  2. React学习笔记-1-什么是react,react环境搭建以及第一个react实例

    什么是react?react的官方网站:https://facebook.github.io/react/下图这个就是就是react的标志,非常巧合的是他和我们的github的编辑器Atom非常相似. ...

  3. React系列(一):React入门

    React简介 1.由来 React是有Facebook开发出来用于构建前端界面的JS组件库,由于其背后的强大背景,使得这款库在技术开发上完全没有问题. 2.React的优势 解决大规模项目开发中数据 ...

  4. React Native是一套使用 React 构建 Native app 的编程框架

    React Native是一套使用 React 构建 Native app 的编程框架 React Native at first sight what is React Native? 跟据官方的描 ...

  5. react.js 从零开始(七)React (虚拟)DOM

    React 元素 React 中最主要的类型就是 ReactElement.它有四个属性:type,props,key 和ref.它没有方法,并且原型上什么都没有. 可以通过 React.create ...

  6. 如何使用TDD和React Testing Library构建健壮的React应用程序

    如何使用TDD和React Testing Library构建健壮的React应用程序 当我开始学习React时,我努力的一件事就是以一种既有用又直观的方式来测试我的web应用程序. 每次我想测试它时 ...

  7. React环境配置(第一个React项目)

    使用Webpack构建React项目 1. 使用NPM配置React环境 NPM及React安装自行百度 首先创建一个文件夹,the_first_React 进入到创建好的目录,npm init,然后 ...

  8. Unite 2017 干货整理 优化篇

    Unite 2017 干货整理 优化篇 2017年05月16日 将Unite 2017的一些演讲做了整理.  本篇有内存,CPU.GC.UI.渲染性能指标.Tips几个小节.  内容持续整理中. 内存 ...

  9. Unite 2017 干货整理 同步篇

    http://www.kisence.com/2017/05/17/unite-2017-gan-huo-zheng-li-tong-bu-pian/ Unite 2017 干货整理 同步篇 2017 ...

随机推荐

  1. 图论:Dinic算法

    解决最大流问题我搜到了一堆的算法:EK算法.FF算法.Dinic算法.SAP算法.ISAP算法 然而并没有什么鸟用 掌握最常见的Dinic就够了,据说极限优化的ISAP比Dinic更快一些..我当不知 ...

  2. CSS3动画(重要)

    CSS3 动画 CSS3,我们可以创建动画,它可以取代许多网页动画图像,Flash动画,和JAVAScripts. CSS3 @keyframes 规则 要创建CSS3动画,你将不得不了解@keyfr ...

  3. Codeforces 362E Petya and Pipes 费用流建图

    题意: 给一个网络中某些边增加容量,增加的总和最大为K,使得最大流最大. 费用流:在某条边增加单位流量的费用. 那么就可以2个点之间建2条边,第一条给定边(u,v,x,0)这条边费用为0 同时另一条边 ...

  4. solaris遇到的问题整理总结

    solaris遇到的问题整理总结 http://zh888.blog.51cto.com/1684752/454326

  5. OSI和TCP/IP的对比+IP地址分类

    一.OSI和TCP/IP对比 二.IP地址分类 A类私有IP地址:10.0.0.0-10.255.255.255B类私有IP地址:172.16.0.0-172.31.255.255C类私有IP地址:1 ...

  6. 2.jinja2

    1.jinja2模板介绍和查找路径 from flask import Flask, render_template import os # 之前提到过在渲染模板的时候,默认会从项目根目录下的temp ...

  7. WPF中添加一个文本输入框,按Enter回车,执行绑定的Command

    在WPF+WMMV模式中使用键盘和鼠标事件的绑定代码如下: <TextBox x:Name="SearchBox" Text="{Binding SearchTex ...

  8. OleDbDataAdapter具体使用

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  9. src2中的alpha融合ROI

    #include <cv.h> #include <highgui.h> int main(int argc, char** argv) { IplImage *src1,*s ...

  10. python Tk()生成的桌面的具体设置方法

    rom tkinter import * root = Tk() root['height'] = 300 #设置高 root['width'] = 500 #设置宽 root.title('魔方小站 ...