React Conf 2017 乾貨總結1: React + ES next = ♥

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

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

這幾方面展開。並經過nodeJS實現一個兼具前端和後端的小型「評論/留言 發佈閱讀系統」。程序員

建議看這篇文章的同時,結合視頻一塊兒研究:Ben Ilegbodu - React + ES next = ♥ - React Conf 2017github

實現預覽

如圖,咱們實現了以下的頁面。這是一個前端+後端的全棧小項目。
固然,樣式是極其簡陋的。做爲「粗糙」的程序員,實在懶得在頁面上花時間。ajax

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倉庫,歡迎經過代碼各類形式交流。

相關文章
相關標籤/搜索