掌握這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的話,我至少能幫你理清思路。

現在揭曉這五大核心概念:

  1. 組件
  2. JSX
  3. Props & State
  4. 組件API
  5. 組件類型

概念一: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全家桶實現一個簡易備忘錄

TAG:React | 前端开发 |