掌握這5大核心概念,你就理解了React
原文鏈接:React』s Five Fingers of Death. Master these five concepts, then master React.
作者:Sacha Greif
幾年前,我的一個朋友向我吹捧有個叫做React的框架會如何革新Web開發。其實一開始我覺得它只是又一個曇花一現的框架罷了。可在之後的時間裡,React名聲鵲起,逐漸變得不容小覷了。
也許你和我之前的狀況差不多:總是聽到React這兒好那兒爽,可是真正坐下來學習React的時候又毫無頭緒。
好消息是我在這裡替你總結了,其實React只有「五大核心概念」。
不過也請不要誤會我的意思,並不是說我一篇文章就能能讓你搖身一變成為精通React的大神,但如果你打算或者正在學習React的話,我至少能幫你理清思路。
現在揭曉這五大核心概念:
- 組件
- JSX
- Props & State
- 組件API
- 組件類型
概念一:React組件的作用
你需要了解有關React的第一要點就是——組件。你編寫的所有React代碼基本上就是一個包含許多小組件在內的大組件。
那麼到底什麼是組件呢?我們可以拿HTML標籤 <select> 來舉一個很恰當的例子。原生的下拉框標籤不止包括邊框、文本、下拉箭頭,它還掌控著自身打開關閉的邏輯。
現在來設想一下你需要構建一個你自定義樣式和行為邏輯的<select>:
這其實就是React能夠幫你做到的。React組件能夠像原生的HTML標籤一樣輸出特定的界面元素,並且也能包括一些元素相關邏輯功能的代碼。
現在我們一般會用ES6的Class語法來聲明一個React組件,它包含一個能夠返回HTML的render方法。(當然也可以用函數聲明,我們在之後會聊到)
class MyComponent extends React.Component {n render() {n return <p>Hello World!<p>;n }n}n
概念二:JSX是什麼玩意兒?
是的你沒看錯,按照上面React組件的示例代碼,React的意思就是讓我們把HTML和JS代碼全都寫在一起。React是通過一種叫做JSX的語法擴展(X代表XML)來實現的。
JSX乍看起來可能很奇怪,不過你慢慢會習慣的。
是的我知道,按照我們以往的傳統,應該盡量把HTML和JavaScript的代碼分開才是。不過看樣子現在忘記這教條才是提高你前端開發效率的正道。
我們還是來舉幾個JSX實際應用的例子吧,比如你可以通過{}大括弧來在JSX中顯示JS變數:
class MyComponent extends React.Component {n render() {n return <p>Today is: {new Date()}</p>;n }n}n
你不再需要什麼前端模板標籤之類的東西了,你可以直接在JSX中使用三元運算符一類的邏輯:
class MyComponent extends React.Component {n render() {n return <p>Hello {this.props.someVar ? World : Kitty}</p>;n }n}n
順便提一句,可能你現在對ES6還不是特別的了解,那麼我推薦你去看看阮老師的ECMAScript 6 入門。
概念三:Props & State又是啥?
你可能會疑惑上個例子里的this.props.someVar是從哪裡冒出來的。
只要你對HTML有所了解,應該能夠理解<a>標籤的href屬性是什麼意思。延伸到React當中,屬性就被稱作props(properties的縮寫)。組件之間可以通過Props進行交互。
class ParentComponent extends React.Component {n render() {n return <ChildComponent message="Hello World"/>;n }n}nclass ChildComponent extends React.Component {n render() {n return <p>And then I said, 「{this.props.message}」</p>;n }n}n
也正因如此,React當中的數據流是單向的:數據只能從父組件傳向子組件,反過來則不行。
可是組件不可能只接受從父組件傳來的數據(例如還有用戶在input當中的輸入),這時state就派上了用場。
原文的例子實在是不接地氣,在這裡我情不自禁想要引用一句古詩來解釋props和state之間的區別:
人有悲歡離合,月有陰晴圓缺。
我們可以把一個人的基因性別名字(我知道某些東西其實是可變的但請不要鑽牛角尖好嗎),月亮的大小重量理解為props,而隨時可變的情感和圓缺則可以被理解為state.
要注意,組件的state同樣也能被傳入到子組件中作為子組件prop的值。你需要明確的就是在React當中整個數據流都是向下傳遞的,包括路由、數據層、各個組件等等,從整個應用的state中來並匯聚到一起。
在組建中,我們可以通過一個叫setState的方法來修改state,一般我們都會在事件處理的方法中調用它:
class MyComponent extends React.Component {n handleClick = (e) => {n this.setState({clicked: true});n }n render() {n return <a href="#" onClick={this.handleClick}>Click me</a>;n }n}n
一般React應用當中的絕大多數數據都是prop,只有當用戶輸入內容時才會使用state來處理。
注意在上述的代碼中,我們使用了自動綁定的語法,如果你想了解更多可以閱讀官方文檔Handling Events.
概念四:組件API
在之前的內容當中我們已經提及了render和setState兩個方法,他們都包含在組件API方法之中。還有一個比較有用的方法constructor,我們一般會在其中初始化state並做一些方法的綁定。
除了這三個方法之外,React還提供了一些列按照特定次序觸發的生命周期函數。不過先不需要擔心,只有當你深入一些了解React之後才有機會使用到它們。
我們並不會在這裡展開篇幅講解React的API,因為學習React更主要的目的是學習如何編程和它的構建理念,而不是死記硬背一些無聊的API方法。
概念五:組件類型
我們在React當中一般按照如下的方法定義一個組件:
class MyComponent extends React.Component {n render() {n return <p>Hello World!<p>;n }n}n
在Class中我們還可以申明一個組件的許多其他方法,而在更多的情況下我們可以寫一種函數式組件。
類似於自定義一個模板標籤一樣,函數式組件接收一個props參數並返回特定的HTML內容,不過你當然仍可以在其中調用一些JS代碼:
const myComponent = props => {n return <p>Hello {props.name}! Today is {new Date()}.</p>n}n
因為通常你的組件可能並不需要多麼複雜的交互,也不需要多餘的其他方法,用函數式寫法可以讓你的代碼更加簡潔。
當然在這樣的組件當中你也沒有辦法使用setState方法,也即是說函數式組件沒有state,所以也可以被稱作是無狀態組件。
當然,如果你接觸React比較早,可能也見過下面這種寫法:
var Greeting = React.createClass({ nn render: function() { n return <h1>Hello, {this.props.name}</h1>; n }n});n
不同的組件類型也就延伸出了組件角色的概念,人們在實踐過程中開始將組件分為兩種角色,一種關注UI邏輯,用來展示或隱藏內容;另一種關注數據交互,例如載入伺服器端的數據。
這兩種組件被稱作容器組件和展示組件。分別用來處理不同的業務邏輯:
//presentational componentnnclass CommentList extends React.Component {n constructor(props) {n super(props);n }nn render() { n return <ul> {this.props.comments.map(renderComment)} </ul>;n }nn renderComment({body, author}) {n return <li>{body}—{author}</li>;n }n}nn//container componentnnclass CommentListContainer extends React.Component {n constructor() {n super();n this.state = { comments: [] }n }nn componentDidMount() {n $.ajax({n url: "/my-comments.json",n dataType: json,n success: function(comments) {n this.setState({comments: comments});n }.bind(this)n });n }nn render() {n return <CommentList comments={this.state.comments} />;n }n}n
這就又有點類似於view/controller的概念了。不過說來說去只是構建代碼的不同方式而已,區分邏輯當然有其好處(例如分離業務邏輯,更好的代碼復用),當然你也可以完全不吃這一套。
高階組件
最後我們再稍微涉獵一些高階組件的概念(higher-order components通常縮寫為HOCs)。
其實可以把它理解為一個工廠方法,你可以傳入一個組件並得到一個HOC返回的附加了更多功能的新組件。HOC不能直接在render方法中調用。如果你想了解更多,可以去看react-router當中實際應用的例子。
這裡還有一篇深入理解 React 高階組件。
總結
- React的代碼是由一個個的組件構成的。
- 組件採用了JSX語法擴展的寫法。
- 數據流總是從父組件到子組件,除state可以通過調用方法修改之外。
- 組件包含一些特定方法和生命周期函數。
- 你也完全可以用函數聲明只有render方法的無狀態組件。
- 區分處理UI和數據邏輯的組件是一種很好的開發實踐。
- 高階組件函數可以傳入一個組件並為其賦予更多功能。
信不信由你,目前我們介紹的內容已經涵蓋了React開發者在日常工作中應用的90%的知識。聽起來可能有些晦澀抽象,單React當中涉及的內容總能被簡化為functions和props.
等到你真正理解這些知識之後,React也就不會那麼可怕了。在你掌握了React的模式,瞟一眼就能看懂它的代碼之後,也就能自信的裝X:
切,React已經out啦~
更多有關React的資源鏈接:
- react-redux-links
- awesome-react
有任何好的意見建議或有關React的想法觀點,歡迎在評論區參與討論。
推薦閱讀:
※React 模態框秘密和「輪子」漸進設計
※高性能 MobX 模式(part 3)- 用例教程
※React 許可證雖嚴苛,但不必過度 react
※React全家桶實現一個簡易備忘錄