本文是『horseshoe·React專題』系列文章之一,後續會有更多專題推出
來個人 GitHub repo 閱讀完整的專題文章
來個人 我的博客 得到無與倫比的閱讀體驗
話說PHP是世界上最好的語言(笑)。javascript
由於它的入門門檻極低。php
<?php $str = '<ul>'; foreach ($fruits as $fruit) { $str += '<li>' . $fruit . '</li>'; } $str += '</ul>'; ?>
不少年前,這種字符串拼接開發網頁的方式很是流行。html
可是這種寫法有兩個問題:前端
因而facebook的工程師開始動歪腦筋了。vue
他們的解決方案也很新穎,就是在代碼裏直接寫標籤,而不是將標籤視爲字符串。java
前面說到,字符串拼接很容易形成XSS注入。那麼什麼是XSS注入呢?react
好比惡意用戶輸入這麼一段內容:<script>code</script>
,就可能被程序識別爲一段腳本,他能夠在腳本里面幹任何事情。git
因而人們想到的辦法是對全部輸入轉義,轉義的做用就是讓全部標籤沒法被識別爲標籤,而只是標籤寫法的字符串。用戶的輸入就會原本來本的展現在頁面上。github
可是輸入轉義也有問題,就是容易把字符串拼接的標籤也給轉義了。你們應該看過頁面上大段大段的標籤寫法的文本吧。數組
咱們來看看XHP的寫法。
<?hh $post = <div class="post"> <h2>{$post}</h2> <p><span>Hey there.</span></p> <a href={$like_link}>Like</a> </div>;
誒,是否是有點眼熟?
XHP把標籤與字符串區別開來了,變成腳本語法的一部分。
這正好解決了前面提到的兩個問題:
其實facebook一直在前端組件化方面作各類嘗試,但都不是特別成功。
直到2013年,工程師Jordan Walke提出一個大膽的想法:把XHP的寫法遷移到JavaScript中來。即使有XHP的案例在前,你們仍是以爲這個想法很瘋狂。
不過,facebook極爲優秀的工程師文化最終促成了這種嘗試。這一嘗試不得了,開了天眼。
自此以後就開啓了React的開掛之路。
const element = <h1>Hello React!</h1>;
這不就是facebook一直在苦苦求索的前端組件化方案嗎?
刀耕火種時期的前端,入口是HTML,腳本和樣式被引入到HTML頁面上。這是一種分離化的思想,以語言爲最小顆粒。
然而通過大量痛苦的實踐,人們發現之內容爲最小顆粒纔是正解。以組件爲單位,頁面結構、樣式和功能都被集成在組件內部,對開發者來講組件就是一個黑匣子,只能經過暴露出來的接口使用組件。這是一種封裝的思想,目的固然是爲了複用。
固然,目前React還沒法實現真正意義上的CSS封裝,不過以當下前端的關注度,CSS被完全招安也指日可待。
標籤的寫法和HTML同樣,只不過融入到了JavaScript中。
組件,其實就是自定義標籤,首字母必須大寫,爲了與原生標籤區別開來。
若是標籤或組件沒有包含內容,能夠採用自閉合標籤寫法。
const element = <App />;
JSX會自動忽略false
、null
和undefined
。
標籤的class
屬性和for
屬性要用className
屬性和htmlFor
屬性代替。
組件返回多個標籤或多個組件必需要用一個標籤或組件包裹,也就是說只能有一個頂層元素。
可是,React16以上的版本支持用空標籤包裹或者直接返回數組。這樣的好處就是沒必要添加不少無用的標籤使頁面變得更加臃腫。
import React, { Fragment } from 'react'; const App = () => { return ( <Fragment> <div>React</div> <div>Vue</div> <div>Angular</div> </Fragment> ); } export default App;
import React from 'react'; const App = () => { return ( <> <div>React</div> <div>Vue</div> <div>Angular</div> </> ); } export default App;
import React from 'react'; const App = () => { return [ <div key="1">React</div>, <div key="2">Vue</div>, <div key="3">Angular</div>, ]; } export default App;
標籤裏確定要寫一些變量,要否則頁面就是死的。
怎麼寫變量呢?用花括號包圍。
const name = 'React'; const element = <h1>Hello {name}!</h1>;
若是我想插入一個對象字面量怎麼辦?
很簡單,再包裹一層花括號。
const obj = { name: 'React' }; const element = <h1 style={{ color: '#f66' }}>Hello {name}!</h1>;
實際上花括號語法支持全部的表達式。
那麼問題來了,什麼是表達式?
簡單來說,表達式的主要做用是計算和聲明,老是有返回值。與之相對,語句的主要做用是邏輯和動做,沒有返回值。
如下表達式JSX都支持。
const a = <button onClick={() => console.log('react')}>click</button>; const b = <button onClick={function (){ console.log('react') }}>click</button>; const c = <div>{popular ? 'react' : 'vue'}</div>; const d = <div>{popular && 'react'}</div>; const e = <div>{renderSomething()}</div>;
像賦值語句、判斷語句和循環語句JSX都不支持。
那開發者要渲染一個列表怎麼辦?
for循環語句確定是不行的,好在咱們有map函數。由於從上例咱們知道,JSX是支持函數執行表達式的。
forEach函數行不行呢?不行,由於它沒有返回值。也就是說,filter、find、reduce等有返回值的遍歷函數都是能夠的。
import React, { Component } from 'react'; const list = ['react', 'vue', 'angular']; class App extends Component { render() { return ( <div>{list.map(value => <div key={value}>{value}</div>)}</div> ); } } export default App;
不知道大家有沒有這樣的疑問:
React
這個變量的狀況下還要import React
?這裏就要講到JSX的編譯。
由於JSX不是正確的JavaScript語法,它要通過編譯才能被瀏覽器識別。
目前JSX的編譯工做是由babel來完成的。
咱們來看看編譯都作了哪些工做。
下面的例子,後者是前者編譯後的結果。
const app = ( <div className="form"> <input type="text" /> <button>click</button> </div> );
const app = React.createElement( "div", { className: "form" }, React.createElement("input", { type: "text" }), React.createElement( "button", null, "click", ), );
能夠看到,標籤最後變成了一個函數執行表達式,第一個參數是標籤名,第二個參數是屬性集合,以後的參數都是子標籤。
看到這裏,相信也不用我解釋了,前面提出的兩個問題恍然大悟。
整個UI其實是經過層層嵌套的React.createElement
方法返回的,因此咱們要在文件開頭import React
,不然編譯後就會發現createElement
沒有定義。
React.createElement
執行的結果是一個對象,對象的屬性描述了標籤或組件的性狀,對象再嵌套子對象。若是頂層返回多個標籤,就沒法表達爲一個對象了。
因爲React16引入了Fiber機制,使得返回多標籤成爲可能(並不清楚緣由)。
同時也回答了爲何標籤的class
屬性和for
屬性要用className
屬性和htmlFor
屬性代替。在標籤裏屬性怎麼寫都無所謂,可是class
和for
是JavaScript中的關鍵字,因此要換一種寫法。
React裏面傳遞props有一種寫法,若是傳遞的是一個對象,能夠用擴展運算符很方便的傳遞。
下面的例子,value
先是被擴展運算符將屬性分解,而後又被一個對象包裹。這裏只是作了一個淺拷貝,並無其餘的含義。因此最終傳遞給組件的仍然是一個對象。
因此疑問就來了,一般給組件傳遞屬性都是鍵值對的形式,直接傳遞一個對象也能夠嗎?
其實全部的屬性最後都會放到一個對象裏面,因此兩種寫法異曲同工。React只不過給了一種快捷方式。
瞭解編譯的過程,不少寫法都很好理解了。
const value = { a: 1, b: 2 }; const element = <App a={value.a} b={value.b} />;
const value = { a: 1, b: 2 }; const element = <App {...value} />;
React專題一覽