React作為時下最熱的前端框架,各位有什麼經驗分享下嗎?

我們團隊開發要用這個技術,希望和各位大牛交流下。


如果是技術選型調研的話,除了好處也應該了解一些需要注意的問題吧,下面隨便列列,僅供參考。

1. 不要陷入糾結工具的怪圈

我們團隊一開始用 React 的時候,工具棧應該是 grunt + grunt-react;寫了一段時間感覺有局限,然後老大帶頭把工具換成了 gulp + browserify + watchify + reactify,然後又愉快的寫了大概半年吧,發現流行的庫都上 webpack 了;於是我們的工具棧又變成了 gulp + webpack + babel-loader。最後大家一致認為 gulp 是多餘的,所以我們的工具棧又圍繞 webpack 重新搭建了一遍。到最近我負責的一個內部項目,什麼 hot-module-replacement、extract-text-plugin(讓你在 js 里 require("style.scss"); 這麼寫的玩意兒)一股腦的造。當然再後來因為業務需要我們又基於 webpack 搭建了自己的構建工具,這是後話……

這將近一年半的折騰歷史告訴大家,1) 前端就是個大坑,1個月不學新知識你就會被社區遺忘 2) 現在上 React 真幸福,工具棧基本都穩定了(什麼?你還不懂?用 webpack!),不用花太多時間糾結。

PS. HMR 也就那樣,雖然 dan 吹得神乎其神,但實際在項目里我發現大家還是習慣手動 Cmd + R

,因為項目大了以後 rebuild 也需要 1、2 秒。

2. DOM 操作是不可避免的

但凡是上點兒規模的前端項目,沒有 DOM 操作基本是不可能的。且不說最常見的後端「埋點」,你總得用 DOM API 去取值吧;就說一個最簡單的,比如右手邊這個「回到頂部」的按鈕,你純用 React 寫一個試試。當然你會說什麼 requestAnimationFrame,什麼 ReactCSSTransitionGroup blah blah blah,真正到項目里你會發現還是 DOM API 簡單。

3. 擁抱 ES 6,擁抱 React v0.14

這倆為什麼放在一起說呢?因為 React v0.14 里提出了一個全新的組件概念叫做:無狀態的函數式組件(Stateless functional components)。它大概長這樣:

var Aquarium = ({species}) =&> (
&
{getFish(species)}
&

);

有沒有發現被傳統的 createClass 方法精簡了很多?當然這樣寫組件也有很多局限,比如不能聲明各種生命周期方法等等,但是在常見的前端業務場景中,純 render 的組件不在少數。在這樣的語法推出後,我們就能把這些組件更方便的抽出來複用了。

此外,擁抱 ES 6 還有很多的好處,比如在載入依賴的時候不用先 var xxx = require("xxx"); 再 var yyy = xxx.yyy; 而是可以直接 import {yyy} from "xxx"; 簡潔明了。

4. 生態環境仍然在成長中,坑不少

其中首先要口誅筆伐一下的就是 react-router,我們從 v0.10 開始用,到現在 v1.0。你知道為了升級這玩意兒我們改了多少次業務代碼么?每次升級 API 都要變,無力吐槽。當年好不容易搞懂了 v0.11,在博客里寫了篇技術文章分享,結果後面的日子就是各種被催更……一個月前抽空就 0.13 版又重寫了一遍教程,這不 1.0 版又出了,API 基本全都不一樣了!!不一樣了!!一樣了!!樣了!

當然除了坑也有不少高質量的生態環境產品,比如螞蟻的 ant design。

5. Server 端渲染很美,至今沒看見哪個規模級的產品用到

可能是我孤陋寡聞吧,歡迎評論中跟進。自己摸索著寫過一個最簡單的 server 端渲染,但是這套邏輯如果套到我們現在的業務邏輯中,幾乎可以直接槍斃。為了實現 server 端渲染需要做出的 trade off 太多。

6. React 很簡單,也很難

簡單是因為 React 的 API 真的很少,官網的各種文檔花一個下午也能看個七七八八(此時此刻再看看 Angular……)。但是當你以為你真的搞懂 React 的時候,看看React 源碼剖析系列 - 解密 setState - pure render - 知乎專欄這篇文章開頭提的問題,有多少人能不假思索的答對呢?(順便安利一下,我們團隊的知乎專欄,目前處於死磕 React 的狀態)

當你真正在業務項目中使用 React 的時候,你會發現它的生命周期比你想像的複雜;它的 API 背後的邏輯比你以為的麻煩。當然,首先你要踩進這個坑。

7. 對於樓上某位仁兄表示《React:引領未來的用戶界面開發框架》這本書太難的回答,作為譯者之一表示對不起你。作為補償,所有購買本書的同學均可憑拍照私信我諮詢 React 相關的問題。

最後再次安利一下我們團隊的專欄: pure render - 知乎專欄

8. 夢中驚醒補充一點,截止目前為止,Babel 6 是個大坑,業務中使用的時候一定要注意其與 Babel 5 的巨大區別。(關於補充的這一點,再額外的闡述一下,應該理解成 Babel 5 為了讓大家愉快的用上 ES 6 做了一些非標準的轉換,這些轉換在 Babel 6 中都去掉了。所以你在 Babel 5 下面編譯正常的代碼在 Babel 6 編譯時可能就會出錯。這個問題不能確切的算作 Babel 的坑,但是會影響你的開發進度)


謝邀~

這些只是我自己寫項目中的一些原則和習慣,歡迎指正

1.能做成組件就盡量做成組件,細分化,do one thing and do it well;還能復用

2.基於第一點,只傳入必要的props, 再使用immutablejs或者react.addons.update來實現不可變數據結構,再結合React.addons.PureRenderMixin來減少reRender

3. 在shouldComponentUpdate中優化組件減少reRender

4. context雖然沒有官方文檔,但還是很好用的。(不會的同學可以自己google react context)

5. 能不做dom操作就盡量不要,始終讓UI能夠基於State還原,盡量在render()中把該做的做好

6.propTypes, defaultProps不要懶的去寫,別人通過你的propTypes很容易理解組件,也容易debug

7. 在store和action中不要有dom操作或者訪問window.屬性,讓store和action中的邏輯只與數據打交道,好處:測試,伺服器端渲染

8.推薦使用ES6,arrow function"=&>"和destructuring {...this.props} var {a,b}=this.props很好用

9. npm的debug包前後端公用很方便,開發的時候把組件渲染的每個步驟和動作都log下來,很容易在開發的時候就發現問題

10. 使用es6時,事件handler盡量不要用這樣偷懶的寫法onClick={e=&>(this.doSomething("val"))},如果傳遞這個function給子組件,子組件就沒法用PureRenderMixin來減少重複渲染了,因為這是個匿名函數

暫時想到這麼多


React.js 作為前端框架的後起之秀,卻在2015年攜著虛擬 DOM,組件化,單向數據流等利器,給前端 UI 構建掀起了一波聲勢浩大的函數式新潮流。新鮮出爐的一篇 React.js 最佳實踐,基本涵蓋了所有的 React.js 生態周邊,可用於實踐參考。文章不僅表明了 Flux 經常被濫用的觀點,也推薦開發者使用 Redux 作為 JavaScript 的可預測狀態容器,並且提出保持狀態扁平化和使用 Immutable.js 等數據處理解決方案。與此同時,也從高階組件,組件測試以及組件級別熱重載等方面提供了建議,當然也涉及了 Webpack,HTTP 2,使用 ES2015 乃至 Linters 等代碼層面的建議。

不得不吐槽知乎編輯器的渣渣功能,更佳閱讀效果,可以到我的博客看雙語版:【譯】展望2016,React.js 最佳實踐 (中英對照版)

------

【譯】展望2016,React.js 最佳實踐

原文地址:&

過去的2015年,React 在全世界範圍都是一派欣欣向榮的景象,開發者會議無一不熱衷於這個話題。在過去一年中發生了很多重要的里程碑事件,更多詳情可以查看我們關於 React in 2015 的總結。

在新的2016年里,最有趣的問題來了:我們該如何開發一個應用,有什麼推薦使用的庫?

作為一名長時間使用 React.js 的開發者來說,我對這個問題有自己的答案以及最佳實踐,但也有可能你不會完全認同。我也非常樂於傾聽你的想法和觀點:請留言以便討論。

如果你才剛剛開始學習 React.js,可以查看我們的 React.js 教程,或者 Pete Hunt 所寫的 React howto React ecosystem.)。

數據處理

在 React.js 應用中處理數據輕而易舉,與此同時亦充滿挑戰。這是因為你可以通過各種方式將屬性數據傳遞給 React 組件,並從中構建渲染樹;然而這種方式也並非那麼顯而易見,到底該如何更新視圖。2015之初誕生了很多不同 Flux 庫,並不斷產出了更加實用的響應式方案。

讓我們看看現在的情況:

Flux

根據我們的經驗,Flux 經常被濫用,(這意味著大家總是在不需要的時候就用上它)。

Flux 提供了一種非常清晰的方式來存儲和更新應用狀態,並且只會在必要的時候才觸發頁面渲染。

Flux 致力於應用的全局狀態管理,比如:管理已登錄用戶狀態,路由狀態,或者是活躍賬戶狀態,但若是用來管理臨時數據或者本地數據,瞬間就變成了痛苦。

我們不推薦使用 Flux 來管理路由相關的數據,比如 /items/:itemId。而只是獲取路由數據並存儲在組件的 state 之中。在這種情況下,它會在組件消失之後一起被銷毀。

如果你想了解更多關於 Flux 的信息,The Evolution of Flux Frameworks 非常值得一讀。

使用 Redux

Redux 是一個 JavaScript 應用的可預測狀態容器。

如果你覺得需要 Flux 或者一種類似的解決方案,你應該了解一下 redux,以及學習 Dan Abramov 的Getting started with redux 課程,這能夠迅速提高你的開發技能。

Redux 延續並改進了 Flux 的思想,並從 Elm 架構中取經,規避了 Flux 的複雜度。(譯者註:Elm 是一門面向 Web 的函數式編程語言,致力於改善客戶端 Web 編程體驗。)

保持狀態扁平化

API 經常會返回嵌套資源。這在 Flux 或基於 Redux 的架構中處理起來會非常困難。我們推薦使用 normalizr 之類的庫將數據進行扁平化處理,保持狀態儘可能地扁平化

示意:

const data = normalize(response, arrayOf(schema.user))

state = _.merge(state, data.entities)

(我們使用 isomorphic-fetch 來與 APIs 進行交互)

使用 immutable 狀態

共享的可變性狀態乃萬惡之源。 —— Pete Hunt, React.js Conf 2015

不可變對象是一種在創建之後就不可修改的對象。不可變對象可以讓我們免於痛楚,並通過引用級別的比對檢查來改善渲染性能 。比如說在 shouldComponentUpdate 中:

shouldComponentUpdate(nexProps) {
// instead of object deep comparsion
return this.props.immutableFoo !== nexProps.immutableFoo
}

如何在 JavaScript 中實現不可變呢?

最痛苦的方式就是小心為之,示例代碼如下,你需要在單元測試中通過 deep-freeze-node 來反覆驗證。(在修改之前凍結,並在結束後驗證結果。)

return {
...state,
foo
}

return arr1.concat(arr2)

相信我,這是最平淡無奇的例子了。更簡單也更自然的方式就是使用 Immutable.js。

import { fromJS } from "immutable"

const state = fromJS({ bar: "biz" })
const newState = foo.set("bar", "baz")

Immutable.js 非常之快,背後理念也異常漂亮。哪怕你並不想使用它,我也推薦閱讀這個由 Lee Byron 所製作的視頻 Immutable Data and React。視頻對於 Immutable.js 的工作原理有著非常深刻的講解。

觀察式與響應式方案

如果你不喜歡 Flux/Redux 或者只是想要更加 reactive,不要失望!這兒有很多其他數據處理的解決方案。這就有一個相關庫的簡要列表供你參考:

  • cycle.js(「A functional and reactive JavaScript framework for cleaner code」)
  • rx-flux(「The Flux architecture with RxJS」)
  • redux-rx(「RxJS utilities for Redux.」)
  • mobservable(「Observable data. Reactive functions. Simple code.」)

路由

幾乎所有的客戶端應用都或多或少需要使用路由。如果你在瀏覽器中使用 React.js,你就會在挑選庫的時候碰到這個分歧點。我們的選擇是出自優秀的 rackt 社區的 react-router。Racket 給 React.js 的擁簇者帶來了很多高質量資源。

你可以查看他們的文檔以便於集成 react-router,但是更重要的是:如果你使用 Flux/Redux,我們建議你將路由狀態和你的 store 或全局狀態保持同步

同步的路由狀態可以幫助你對 Flux/Redux 的 Actions 所提供的路由行為有所控制,並且能夠在組件中讀取路由狀態和參數。

Redux 用戶可以通過 redux-simple-router 這個庫輕鬆實現它。

代碼分割,惰性載入

只有一小部分 webpack 用戶知道應用代碼是可以分割的,將 bundler 的輸出拆分成多個 JavaScript 塊:

require.ensure([], () =&> {
const Profile = require("./Profile.js")
this.setState({
currentComponent: Profile
})
})

這在大型應用中會非常有用,因為在每次部署之後,用戶瀏覽器就沒有必要下載那些很少用到的代碼,比如 profile 頁面。

更多代碼塊將導致更多 HTTP 請求 —— 但是使用 HTTP/2 multiplexed 的話就不成問題。結合 chunk hashing,你也可以在代碼改變之後優化緩存命中率。(譯者註:終端用戶訪問加速節點時,如果該節點有緩存住了要被訪問的數據時就叫做命中,如果沒有的話需要回原伺服器獲取,就是沒有命中。)

react-router 的下個版本就將在代碼分割這方面提供更多幫助。

想要了解 react-router 的未來走向,可以查看 Ryan Florence 所寫的這篇博文: Welcome to Future of Web Application Delivery。

組件

大部分人都對 JSX 存有怨言。首先,你需要知道的是這在 React 中並不是必須的。在最後,JSX 都會通過 Babel 被編譯成 JavaScript。你可以直接編寫 JavaScript 來替代 JSX,但是在處理 HTML 的時候使用 JSX 會感覺更加自然。

特別是對於不懂技術的人來說,他們依然可以理解和修改必要的部分。

JSX 是一種與 XML 類似的 JavaScript 語法擴展。你可以通過一個簡單的 JSX 語法轉換器來編譯 React。 —— JSX in depth

如果你想要了解更多關於 JSX 的信息,可以查看 JSX Looks Like An Abomination - But it』s Good for You 這篇文章。

使用 Class

React 和 ES2015 的 Class 語法搭配完美。

class HelloMessage extends React.Component {
render() {
return &Hello {this.props.name}& }
}

我們喜歡高階組件更勝於 mixins,所以對於我們來說,保留 createClass 就更像一個語法問題而不是技術問題。我們相信使用 createClass 而不是 React.Component 絕對無可厚非,反之亦然。

屬性類型

如果你在2016年依然沒有檢查 properties,那麼你應該從現在開始做起,這將為你節省大量時間,相信我。

MyComponent.propTypes = {
isLoading: PropTypes.bool.isRequired,
items: ImmutablePropTypes.listOf(
ImmutablePropTypes.contains({
name: PropTypes.string.isRequired,
})
).isRequired
}

當然,驗證 Immutable.js 所編寫的 properties 也是可能的,可以使用react-immutable-proptypes。

高階組件

目前來說,mixins 已死,而且在 ES6 Class 組件中已經不再被支持,我們應當尋找不同的替代方案。

那什麼是高階組件呢?

PassData({ foo: "bar" })(MyComponent)

本質上來說,你可以由原始組件創造一個新的組件並且擴展它的行為。你可以在多種情況下使用它,比如授權:requireAuth({ role: "admin" })(MyComponent) (檢查上層組件中的用戶,若是未登錄則需要重定向),或者是連接你的組件和 Flux/Redux 倉庫。

在RisingStack,我們也將數據獲取和類似 Controller 的邏輯分割成高階組件,並保持視圖層儘可能簡單。

測試

在開發周期中,維持測試的高覆蓋率是非常重要的一部分。幸運的是, React.js 社區誕生了很多優秀的庫可以幫助我們達到這一點。

組件測試

我們最喜愛的庫之一是由 AirBnb 所開發的 enzyme,可用於組件測試。非常神奇的是,它的淺渲染特性可以對組件的邏輯及其渲染輸出進行測試。儘管它還不能替代你的 selenium 測試,但是將前端測試提升到了一個新的水平。

it("simulates click events", () =&> {
const onButtonClick = sinon.spy()
const wrapper = shallow(
&
)
wrapper.find("button").simulate("click")
expect(onButtonClick.calledOnce).to.be.true
})

看起來就非常簡潔,不是么?你在使用 chai 作為測試斷言庫嘛?相信你會喜歡 chai-enyzime 的!

Redux 測試

測試一個 reducer 非常簡單,它響應新到來的 actions,並且將原來的狀態進行更新:

it("should set token", () =&> {
const nextState = reducer(undefined, {
type: USER_SET_TOKEN,
token: "my-token"
})

// immutable.js state output
expect(nextState.toJS()).to.be.eql({
token: "my-token"
})
})

測試 actions 也很簡單,但是非同步 actions 就不太一樣了。對於測試非同步的 Redux actions 來說,我們推薦使用 redux-mock-store,非常有幫助。

it("should dispatch action", (done) =&> {
const getState = {}
const action = { type: "ADD_TODO" }
const expectedActions = [action]

const store = mockStore(getState, expectedActions, done)
store.dispatch(action)
})

更深度地了解 redux 測試,可以查看官方文檔。

使用 npm

雖然 React.js 並不依賴代碼打包工具就可以很好地工作,但我們還是推薦使用 Webpack 或者 Browserify 來發揮 npm 的能力。Npm 上滿是高質量的 React.js 包,還可以幫你非常優雅地管理依賴。

(請不要忘記復用你自己的組件,這是一種絕佳的代碼優化方式。)

Bundle 大小

這本身不是一個 React 相關的問題,但是大多數人都在打包他們的 React 應用,所以我認為提到這點很重要。當你打包源代碼的時候,時刻警惕打包後的文件大小。為了保持體積最小化,你應該考慮如何 require/import 依賴。

對比以下代碼片段,這兩種不同的方式對輸出的影響區別巨大:

import { concat, sortBy, map, sample } from "lodash"

// vs.
import concat from "lodash/concat";
import sortBy from "lodash/sortBy";
import map from "lodash/map";
import sample from "lodash/sample";

可以查看這篇文章 Reduce Your bundle.js File Size By Doing This One Thing 獲取更多詳情。

我們也喜歡將代碼分離出至少 vendors.js 和 app.js 兩個文件,因為 vendors 相對於我們的代碼庫來說更新不是那麼頻繁。

將輸出文件名稱進行哈希化處理 (Webpack 中的 chunk hash),並使用長緩存,我們可以大大減少用戶需要下載的代碼大小。結合惰性載入,優化效果可想而知。

如果你還不太熟悉 Webpack,可以查看這本優秀的 React webpack 手冊。

組件級別熱重載

如果你曾經使用過熱載入來編寫單頁面應用,當你在處理某些與狀態相關的事情時,可能你就會明白當你在編輯器中點擊保存,整個頁面就重新載入了是多麼令人討厭。這樣子就不得不重新點擊一遍應用,重複如此會令人抓狂的。

通過 React,在重載組件的同時保持組件狀態已經成為可能 —— 耶,從此不再痛苦!(沒有蛀牙!)

關於如何搭建熱重載,可以參考 react-transform-boilerplate。

使用ES2015

前面有提到過,我們可以在 React.js 組件中使用 JSX,然後使用Babel.js進行編譯。

其實 Babel 的能力遠不止如此,它也可以讓我們現在就可以給瀏覽器編寫 ES6/ES2015 代碼。在 RisingStack,我們在伺服器端和客戶端都使用了 ES2015 特性,這都已經在最新的 LTS Node.js 版本中被實現了。

Linters

或許你已經給你的 JavaScript 代碼制定了代碼規範,但是你知道也有用於 React 的代碼規範了嗎?我們強烈推薦挑選一個並開始遵循它。

在 RisingStack,我們也將 linters 強制運行在 CI 系統上,git push 亦然。可以試試 pre-push 或者 pre-commit。

我們使用標準的 JavaScript 代碼風格,並使用了 eslint-plugin-react對 React.js 代碼進行規範 。

(就是,我們不再使用分號。)

GraphQL 和 Relay

GraphQL 和 Relay 相對而言屬於新技術,在 RisingStack,目前我們還沒有在產品環境中使用它們,暫時保持關注。

我們曾經寫過一個 Relay 的 MongoDB ORM庫,叫做 graffiti,可以使用已有的 mongoose 模型直接創建一個 GraphQL 伺服器。

如果你想要學習這些新技術,我們建議你可以找來玩一玩。

盡情享用這些 React.js 最佳實踐

有些突出的技術和庫其實跟 React.js 並不相關 —— 但是保持視野開闊,關注社區的其他人都在做些什麼。React 社區在2015年里就受到了 Elm 架構 的很多啟發。

如果你知道其它在2016年必不可少的 React.js 工具,請留言讓我們知道!

-------

原作者: Péter Márton

CTO at RisingStack, brewing beer with Node.js


用了半年,講下真正的經驗,其他的規則都很簡單:

1.最重要的就是用Redux不要抄近道,改寫reducer走事件的一定要走

2.一條金科玉律是一個組件如果不用某個數據來渲染,它就不應該知道它。

3.一定要理解React為什麼叫React,它是一個半調子Reactive library,需要你手動將事件綁定至數據頂層,這與真正的Reactive Programming不同,所以自然地引出了Flux或者Redux。只有真正理解了這點,才能老老實實地按照Redux模式編寫。或者乾脆覺得Redux太SB去寫Cycle了。一定不要抄近道,Redux的綁定在Redux這種架構下都是必要的。


react使用了半年,說下自己的感受:

1. 組件化

react的組件非常方便復用,就想堆積木一樣,對於代碼的復用做得很好

2. 單向流動

與angualr一樣,react也是通過數據來驅動UI,不同之處在於其是單向流動,對代碼可以有很好的預測性,只能通過this.setState來改動UI

3. state管理

react只專註於view層,因此對model的管理就需要額外引入flux、redux等應用框架,尤其是redux,內部只有一個store,原則上state是不可修改的,避免引用帶來的副作用,只能通過dispatch(action)來改變state的狀態

4. 同構應用

目前在公司內部項目中進行了嘗試,使用react+browserify+redux+react-router+immutable+factor-bundle+postcss等技術棧。 通過react-router來方便進行router管理,在node端根據url找到匹配的component,然後並發獲取首屏渲染數據,根據初始化數據創建store,最後使用ReactDOM.renderToString,得到渲染的字元串,最後進行字元串拼接,將完整的html返回瀏覽器

5. 人性化

react內部的有很好warning、error提示,可以方便定位、查詢問題

6. 大前端

工作內部很多人在研究RN,個人沒有使用過,可能會成為一種發展趨勢

7. 生態

react的生態系統不斷在發展壯大,已經有不少很好用的工具

8. 入門簡單

曾經折騰過三個月的angular,發現angular的學習曲線比react陡峭的多,當然想搞懂react內部工作流還是很難的,生命周期內部實現到現在還沒弄徹底清楚


看了"eisneim" 同學的傾囊相助,頓時感覺自己也需要分享下。下面是我曾經寫過的一篇軟文,裡面總結了我們在使用React的過程中對團隊開發起約束作用的一些規範。

React的API非常簡單,然而React的思想卻比較獨特,如:組件化開發、單向數據流、虛擬DOM,能準確理解React的思想並使用其完成開發並不容易,現從四個維度總結React開發中一些符合其思想的開發技巧:組件封裝、數據流、事件系統和JSX。

組件封裝

React通過自定義標籤的方式來實現組件化,組件是React的基礎,React通過組件來構建虛擬DOM、並對數據流做控制。React組件的結構類似於HTML標籤,並支持使用所有常用的HTML標籤和SVG標籤,標籤支持的屬性包括HTML標準屬性、SVG標準屬性和所有的data-*、aria-*屬性。

組件的封裝能更好發揮React的性能優勢和提升開發效率,封裝React組件時應當遵循三個原則:高復用性原則、少組件原則和大組件原則。高復用性原則要求對項目中所有Web頁面的結構有清晰的把握,能夠準確提取樣式或功能雷同的模塊並將其封裝成組件;少組件原則是指當深層次的成員無需組件化時,可以直接將外層的父元素組件化以減少組件的數量,少組件原則是基於開發效率的考慮;大組件原則是指應當更多地將零散組件拼裝成更大的組件,這樣可以簡化組件的調用,在團隊開發中能明顯提升開發效率。

數據流

React的數據模型分為共有數據和私有數據,共有數據可以在組件間進行傳遞,私有數據為當前組件私有。共有數據在React中使用props對象來調用,它包含標籤所有的屬性名稱和屬性值,props對象有三個特性,單向流動性、顯示傳遞性和只讀性。單向流動性是指React的數據只能由父組件傳遞到子組件,而不能由子組件傳遞到父組件;顯示傳遞性是指必須明確地在子組件中通過屬性賦值,數據才可以傳遞到子組件;只讀性是指props數據是只讀的,數據修改後並未改變原始的數據模型,而是會新生成一份數據模型,並將新的數據模型載入到原始父元素,從而完成數據的傳遞和組件狀態的更改。私有數據為組件私有,在React使用state對象來調用,state數據模型可以方便地進行更新操作,並且不會影響到其他組件。

基於React數據模型的特點,在使用React時可以根據數據的更新頻率將數據分為固定數據(更新頻率較低的數據)和動態數據(更新頻率較高的數據)兩類,固定數據使用props對象存儲,動態數據使用state對象來存儲。對數據切分時,props的優先順序要高於state,這樣可以儘可能地保證組件的無狀態化,從而簡化組件的交互邏輯。

事件系統

React中的事件可以分為三類:React合成事件、生命周期事件和其他平台事件。

React合成事件:合成事件機制,是對原生HTML事件進行的封裝,支持絕大部分HTML事件並且跨瀏覽器支持。React合成事件機制的使用類似於原生HTML事件,需要將事件顯示地註冊於組件的標籤上。

生命周期事件:React組件有生命周期的概念,React使用虛擬DOM來管理組件,在內存中完成組件的創建、狀態更新、移除等操作,然後將結果渲染到DOM;React組件的生命周期可以分為4個過程:初始化、掛載、更新、銷毀,每個過程都有一個或多個事件回調,並以回調函數的方式來完成用戶自定義操作。

其他平台事件:包括Window事件和其他插件的事件(如JQuery事件),這些事件可以在React組件內部註冊並與React組件進行通訊,為保持組件的封裝特性,其他平台事件使用時應當與組件生命周期事件的回調函數相結合以實現在React組件內部註冊事件。

使用JSX

JSX是一種語法糖工具,它允許使用標籤化的語言來完成組件和變數的定義。JSX並不是使用React所必須的,可以用原生JavaScript完成React的所有操作。

由於JSX使用了標籤化的語言,相比於JavaScript,它能夠精確地表達出樹的結構,讓代碼變得簡單易懂,還能夠更明確地表達出屬性和數據的傳遞過程。使用JSX對開發效率的代碼的可讀性的提升是很明顯的,尤其是在團隊開發的過程中。

React用具有革命性的創新解決了諸多前端開發的痛點,為更好的發揮React開發的優勢,開發過程應當熟練把握React的設計思想,並始終堅持三點原則:快速開發、高效運行、易於維護。


我買了本書《React:引領未來的用戶界面開發框架》(League of Extraordinary Developers(卓越開發者聯盟))【摘要 書評 試讀】

發現完全不明白,也許這本書不適合入門吧!


2016年React勢如破竹,找個starter項目早點學起來吧!

Awesome-react-boilerplate by jiji262

如果要想知其然又知其所以然,那不妨看看這篇文章:

手把手教你基於ES6架構自己的React Boilerplate項目


貼一段大牛寫的案例分析吧:

原生組件通信原理

React Native通過JavaScript編寫APP的方式,乍看以為是以webview提供的現成的JS與原生語言之間的互調,但是如果當我們調試一個React Native程序的時候,在debug視圖中是不會看到任何webview被調用的痕迹。所以,實際上React Native並沒有使用現成的與webview的通信方法,而是使用了更直接的JS運行環境,比如在iOS中為系統自帶的JavaScriptCore。這與Phonegap這類以webview為主的界面展現與本地能力調用的模式有本質上的區別,也是確保React Native高性能和高效率的基礎。

有了這個核心基礎,我們再來看看React Native是如何通過JS來掛鉤到原生UI和本地能力的。

從上圖很容易可以看到,開發者通過JS去調用一個React Native提供的方法,實際需要先經過兩個橋接封裝類,一個JS的橋接,另一個是原生的橋接。兩個橋接類之間就是通過前面提到的JS運行環境來通信。JS橋接類的作用是將開發者的調用行為加入到React Native的模塊調用隊列,同時生成一個回調的ID。Native橋接類的作用是將隊列里的調用行為取出來根據模塊找到對應的原生UI或者本地能力的函數來執行,並將執行的結果通過回調的ID逐步傳遞到開發者的JS回調函數中。也就是經過這兩個橋接類的相互作用,建立起了JS函數與原生能力的調用序列。

其中不得不提的是React Native進行了虛擬DOM的封裝,所有的視圖的更新都是虛擬DOM做了一個校驗(diff)後最小更新,用內存計算換取UI渲染效率。而開發者可以(不是必須)使用一種叫JSX的語法即可達到像web開發一樣使用標籤和CSS樣式表來開發React Native應用,React Native會將JSX轉化為JS語法通過上述通信流程完成原生UI的渲染和本地能力的調用。

1. var React = require("react-native");

2.

3. var styles = React.StyleSheet.create({

4. text: {

5.
color: "red",

6. backgroundColor:
"white",

7.
fontSize: 30,

8.
margin: 80,

9.
textAlign: "center"

10. },

11. container: {

12.
flex: 1

13. }

14. });

15.

16. class HelloWorld extends React.Component
{

17. render() {

18.
return React.createElement(React.Text, {style: styles.text},
"Hello World!");

19. }

20. }

21.

22. class Main extends React.Component {

23. render() {

24.
return (&

25.
style={styles.container}

26.
initialRoute={{

27.
title: "Property Finder",

28.
component: HelloWorld,

29.
}}/&>);

30. }

31. }

32.

複製代碼

上面的代碼段就是一個React Native的例子。它定義了兩個組件,一個是HelloWorld,一個是Main,其中HelloWorld組件作為Main組件的一部分進行展示。我們可以看到Main組件里有一段XML的標籤,這個語法就是JSX語法,當然,如果不習慣這種語法,也可以完全按照HelloWorld組件的定義,全是使用JS來定義。

另外貼一段另一款開發平台Exmobi針對同樣的需求所使用的實現辦法,因為這款平台是專門針對移動開發的,所以針對性也更強一點。可以參考一下:

ExMobi是通過解析一種叫UIXML的標籤並映射到原生組件的方式渲染窗口和界面,這個解析引擎稱為UIXML引擎,在UIXML中也是支持CSS樣式表和JS語法。

下面的代碼就是一個UIXML代碼文件:

1. &

2. &

3. &

4.
&

5.
&dom數據注入&

6.
&