React-引領未來的用戶界面開發框架-讀書筆記(一)

這本書的主要內容都是以react v0.12為主,ES5語法,筆記中將會使用react v0.14和RS6。

第1章 react簡介

1.本質上是一個狀態機,它以精簡的模型管理復雜的隨著時間而變化的狀態。

2.它不是model-view-controller,它是mvc中的v(view),用來渲染視圖。

3.React運用虛擬的dom實現了一個強大的渲染系統。

4.(1)React就像高性能3d游戲引擎,以渲染函數為基礎。這些函數讀入當前的狀態,將其轉換為目標頁面上的一個虛擬表現。只要react被告知狀態有變化,它就會重新運行這些函數,計算頁面的一個新的虛擬表現,接著自動化把結果轉換成必要的dom更新來反應新的表現。

4.(2)乍一看,這種方式應該比通常的javascript方案(按需更新每一個元素要慢),但react確實是這么做的:它是用了非常高效的算法,計算出虛擬頁面當前版本和新版間的差異,基于這些差異對dom進行必要的最少更新。

5.所以說react贏就贏在了:

  • 最小化了重繪,
  • 并避免了不必要的dom操作,
  • 這兩點都是公認的性能瓶頸。

6.react的虛擬表示差異算法,不但能夠把這些問題的影響降到最低。 ,還能簡化應用的維護成本。當用戶輸入或者有其他更新導致狀態改變時,我們只要簡單的通知react狀態改變了,它就能自動化地處理剩下的事情。我們無須深入到詳細的過程之中。

7.react在整個應用中只使用單個事件處理器,并且會把所有的事件委托到這個處理器上。這一點也提升了react的性能。因為如果有很多時間處理器也會導致性能問題。

第2章 JSX

什么是JSX

JSX即JavaScript XML——一種在React組件內部構建標簽的類XML語法。

與以往在JavaScript中嵌入HTML標簽的幾種方案相比,JSX有如下幾點明顯的特征:

  1. JSX是一種句法變換——每一個JSX節點都對應著一個JavaScript函數
  2. JSX既不提供也不需要運行時庫。
  3. JSX并沒有改變會添加JavaScript的語義——它只是簡單的函數調用而已。



使用JSX前

React.DOM.h1({className: 'question'}, 'Question');                  // v0.11React.createElement('h1', {className: 'question'}, 'Question');     // v0.12

使用JSX之后

<h1 className="question">Queations</h1>;

使用JSX的好處

  1. 允許使用熟悉的語法來定義html元素樹
  2. 提供更佳語義化且易懂的標簽
  3. 程序結構更容易被直觀化
  4. 抽象了react element的創建過程
  5. 可以隨時掌控html標簽以及生成這些標簽的代碼
  6. 是原生的javascript

定義一個自定義組件

const React = require('react');
const ReactDOM = require('react-dom');
class Divider extends React.Component {render() {return (<div classNams="divider"><h2>Questions</h2><hr/></div>)}
}
ReactDOM.render(<Divider></Divider>,document.getElementById('init')
);

使用動態值

JSX將兩個花括號之間的內容{。。。}渲染為動態值。

簡單值:

var text = "Questions"
class Divider extends React.Component {render() {return (<div classNams="divider"><h2>{text}</h2><hr/></div>)}
}
ReactDOM.render(<Divider></Divider>,document.getElementById('init')
);

復雜邏輯使用函數求值:

class Date extends React.Component {
    dataToString = (d) => {return [d.getFullYear(),d.getMonth + 1,d.getDate()].join('-')}render() {return (<h2>{this.dataToString(new Date())}</h2>)}
}
ReactDOM.render(<Date></Date>,document.getElementById('init')
);

react通過將數組中的每一個元素渲染為一個節點的方式對數組進行自動求值。

var text = ['hello', 'world']
class Hello extends React.Component {render() {return (<h2>{text}</h2>)}
}
ReactDOM.render(<Hello></Hello>,document.getElementById('init')
);
// 渲染為 <h2>helloworld</h2>

子節點

將上面介紹過的例子改寫為:

const React = require('react');
const ReactDOM = require('react-dom');
class Divider extends React.Component {render() {return (<div classNams="divider"><h2>{this.props.children}</h2><hr/></div>)}
}
ReactDOM.render(<Divider>Questions</Divider>,document.getElementById('init')
);

注意,后面的示例中我們不會再寫const React = require('react');const ReactDOM = require('react-dom');ReactDOM.render(<Divider>Questions</Divider>,document.getElementById('init'));這幾行代碼。

React將開始標簽與結束標簽之間的所有子節點保存在一個名為this.props.children的特殊組件屬性中。在上面的例子中,this.props.children == ["Questions"]

條件判斷

if/else邏輯很難用HTML標簽來表達,直接往JSX中加入if語句會渲染出無效的JavaScript:

// 這是錯誤的示范
<div className={if(isComplete) { 'is-complete' }}>。。。</div>

而解決的辦法就是使用以下某種方法:

  • 使用三目運算符
  • 設置一個變量并在屬性中引用
  • 將邏輯轉化到函數中
  • 使用&&運算符

使用三目運算符

render(){return(<div className={this.state.isComplete ? 'is-complete' : ''}>...</div>)
}

使用變量

getIsComplete = () => {return this.state.isComplete ? 'is-complete' : '';
}
render(){var isComplete = this.getIsComplete();return(<div className={isComplete}>...</div>)
}

使用函數

getIsComplete = () => {return this.state.isComplete ? 'is-complete' : '';
}
render(){return(<div className={this.getIsComplete()}>...</div>)
}

使用邏輯與(&&)運算符

render(){return(<div className={this.state.isComplete && 'is-complete'}>...</div>)
}

非dom屬性值

key

  • 通過給組件設置一個獨一無二的鍵,并確保它在一個渲染周期中保持一致,使得react能夠更智能地決定應該重用一個組件,還是銷毀并重新創建一個組件,進而提升渲染性能。

ref

  • ref允許父組件在render方法之外保持對子組件的一個引用
  • 在jsx中,你可以通過在屬性中設置期望的引用名來定義一個引用。
render () {return (<div><input ref="myInput" .../></div>);
}

接著就可以在組件中的任何地方使用this.refs.myInput獲取這個引用了(不是真實的dom,是react在需要時用來創建dom的一個描述對象。若要訪問真實的節點,則可以使用:this.refs.myInput.getDOMNode() )

dangerouslySetInnerHTML(隨時可能發生變化)

render () {var htmlString = {__html: "<span>an html string</span>"}return (<div dangerouslySetInnerHTML={htmlString}></div>);
}

事件

在jsx中,捕獲一個事件就像給組件的方法設置一個屬性一樣簡單。

handleClick = (event) => {//...
}
render () {return (<div onClick={this.handleClick.bind(this)}></div>);
}

注釋

jsx的本質就是javascript,所以可以在標簽內添加原生的js注釋。 注釋可以用以下2種形式添加:

  • 1.當做一個元素的子節點
  • 2.內聯在元素的屬性中

1.作為子節點:

<!-- 子節點形式的注釋只需要簡單地包裹在花括號內即可,并且可以跨多行。-->
<div>{/* 這是注釋內容 */}<input type="text" name="" value="" placeholder="">
</div>

2.作為內聯屬性

// 內聯的注釋可以有兩種形式。首先,可以使用多行注釋:
<div><input/*這是多行注釋內容!*/type="text" placeholder="address" />
</div>// 其次也可以使用單行注釋
<div><inputtype="text"  // 這是單行注釋placeholder="address" />
</div>

特殊屬性

  • htmlFor (for)
    • 由于jsx會轉換為js,所以有些關鍵詞我們不能用,比如這個。
<label htmlFor="for-text" ...>
  • className (class)
<div className={classes} ...>

樣式

簡單的駝峰屬性命名即可

render () {var styles = {borderColor: "#888",borderThinkness: "1px"};return (<div style={styles}></div>);
}

如果需要添加瀏覽器前綴瑞 -webkit-、-ms- 大駝峰(除了 ms ), 如:

var divStyle = {WebkitTransition: 'all', // 'W' 是大寫msTransition: 'all'      // 'ms' 為小寫
};

沒有jsx的react

所有的jsx標簽最后都會被轉換為原生的javascript。因此jsx對于react來說并不是必需的。然而,jsx確實減少了一部分復雜性。如果你不打算在react中使用jsx,那么在react中創建元素時需要知道以下三點:

  • 1.定義組件類
  • 2.創建一個為組件類產生實例的工廠
  • 3.使用工廠來創建ReactElement實例

page 19.

第3章 組件的生命周期

React為每個組件提供了生命周期鉤子函數去響應不同的時刻:

  • 1.實例化(創建時)
  • 2.活動期(存在期)
  • 3.銷毀時(被銷毀)

生命周期方法

react組件以簡潔的生命周期api來單單提供你所需要的方法(而不是所有方法)。

實例化

一個實例初次被創建所調用的生命周期方法和其他各個后續實例被創建時所調用的方法略有不同。

所以:當你首次使用一個組件類時,有如下調用順序:

  • getDefaultProps
  • getInitialState
  • componentWillMount
  • render
  • componentDidMount

而該組件類的所有后續應用,將會如下:

  • getDefaultProps
  • componentWillMount
  • render
  • componentDidMount

??區別在于后續的不必執行:getInitialState函數,其余函數如常。(有待進一步理解)

React在ES6的實現中去掉了getInitialState這個hook函數,規定state在constructor中實現,如下:

class App extends React.Component {constructor(props) {super(props);this.state = {};}...}

Babel的Blog上還有一種實現方法,即直接使用賦值語句:

Class App extends React.Component {
constructor(props) {super(props);
}state = {}
...}

存在期

隨著應用狀態的改變,以及組件逐漸受到影響,依次調用如下方法:

  • componentWillReceiveProps
  • shouldComponentUpdate
  • componentWillUpdate
  • render
  • componentDidUpdate

銷毀&清理期

最后,組件被使用完后,componentWillUnmount方法將會被調用,目的是給這個實例提供清理自身的機會。

接下來,應該具體的理解 p24~30的內容(各個時期的各個函數的具體運作)。這里不過多闡述以增加篇幅,只理清思路即可。

我認為這段內容,應該是react的第一塊關鍵內容,乃設計之精心之處,應多多揣摩,爛熟于胸。

由于原書的內容是基于ES5的,下面的章節對使用ES6時的生命周期進行講解:

第二章 - ES6版 React組件生命周期小結

下面所寫的,只適合前端的React。(React也支持后端渲染,而且和前端有點小區別,不過我沒用過。)

相關函數

簡單地說,React Component通過其定義的幾個函數來控制組件在生命周期的各個階段的動作。

在ES6中,一個React組件是用一個class來表示的(具體可以參考官方文檔),如下:

// 定義一個TodoList的React組件,通過繼承React.Component來實現
class TodoList extends React.Component {...
}

這幾個生命周期相關的函數如下:

constructor(props, context)

構造函數,在創建組件的時候調用一次。

componentWillMount()

在組件掛載之前調用一次。如果在這個函數里面調用setState,本次的render函數可以看到更新后的state,并且只渲染一次。

componentDidMount()

在組件掛載之后調用一次。這個時候,子主鍵也都掛載好了,可以在這里使用refs。

componentWillReceiveProps(nextProps)

props是父組件傳遞給子組件的。父組件發生render的時候子組件就會調用componentWillReceiveProps(不管props有沒有更新,也不管父子組件之間有沒有數據交換)。

shouldComponentUpdate(nextProps, nextState)

組件掛載之后,每次調用setState后都會調用shouldComponentUpdate判斷是否需要重新渲染組件。默認返回true,需要重新render。在比較復雜的應用里,有一些數據的改變并不影響界面展示,可以在這里做判斷,優化渲染效率。

componentWillUpdate(nextProps, nextState)

shouldComponentUpdate返回true或者調用forceUpdate之后,componentWillUpdate會被調用。

componentDidUpdate()

除了首次render之后調用componentDidMount,其它render結束之后都是調用componentDidUpdate。

componentWillMount、componentDidMount和componentWillUpdate、componentDidUpdate可以對應起來。區別在于,前者只有在掛載的時候會被調用;而后者在以后的每次更新渲染之后都會被調用。

ReactElement render()

render是一個React組件所必不可少的核心函數(上面的其它函數都不是必須的)。記住,不要在render里面修改state。

componentWillUnmount()

組件被卸載的時候調用。一般在componentDidMount里面注冊的事件需要在這里刪除。

更新方式

在react中,觸發render的有4條路徑。

以下假設shouldComponentUpdate都是按照默認返回true的方式。

  1. 首次渲染Initial Render
  2. 調用this.setState (并不是一次setState會觸發一次render,React可能會合并操作,再一次性進行render)
  3. 父組件發生更新(一般就是props發生改變,但是就算props沒有改變或者父子組件之間沒有數據交換也會觸發render)
  4. 調用this.forceUpdate

下面是我對React組件四條更新路徑地總結:

React組件

注意,如果在shouldComponentUpdate里面返回false可以提前退出更新路徑。

一個React組件生命周期的測試例子

代碼比較簡單,沒有邏輯,只是在每個相關函數里面alert一下。

點擊鏈接來試試這個例子。

源碼

const React = require('react');
const ReactDOM = require('react-dom');
class LifeCycle extends React.Component {constructor(props) {super(props);alert("Initial render");alert("constructor");this.state = {str: "hello"};}componentWillMount() {alert("componentWillMount");}componentDidMount() {alert("componentDidMount");}componentWillReceiveProps(nextProps) {alert("componentWillReceiveProps");}shouldComponentUpdate() {alert("shouldComponentUpdate");return true;        // 記得要返回true}componentWillUpdate() {alert("componentWillUpdate");}componentDidUpdate() {alert("componentDidUpdate");}componentWillUnmount() {alert("componentWillUnmount");}setTheState() {let s = "hello";if (this.state.str === s) {s = "HELLO";}this.setState({str: s});}forceItUpdate() {this.forceUpdate();}render() {alert("render");return(<div><span>{"Props:"}<h2>{parseInt(this.props.num)}</h2></span><br /><span>{"State:"}<h2>{this.state.str}</h2></span></div>);}
}class Container  extends React.Component {constructor(props) {super(props);this.state = {num: Math.random() * 100};}propsChange() {this.setState({num: Math.random() * 100});}setLifeCycleState() {this.refs.rLifeCycle.setTheState();}forceLifeCycleUpdate() {this.refs.rLifeCycle.forceItUpdate();}unmountLifeCycle() {// 這里卸載父組件也會導致卸載子組件React.unmountComponentAtNode(document.getElementById("container"));}parentForceUpdate() {this.forceUpdate();}render() {return (<div><a href="javascript:;" className="weui_btn weui_btn_primary" onClick={this.propsChange.bind(this)}>propsChange</a><a href="javascript:;" className="weui_btn weui_btn_primary" onClick={this.setLifeCycleState.bind(this)}>setState</a><a href="javascript:;" className="weui_btn weui_btn_primary" onClick={this.forceLifeCycleUpdate.bind(this)}>forceUpdate</a><a href="javascript:;" className="weui_btn weui_btn_primary" onClick={this.unmountLifeCycle.bind(this)}>unmount</a><a href="javascript:;" className="weui_btn weui_btn_primary" onClick={this.parentForceUpdate.bind(this)}>parentForceUpdateWithoutChange</a><LifeCycle ref="rLifeCycle" num={this.state.num}></LifeCycle></div>);}
}ReactDOM.render(<Container></Container>,document.getElementById('init')
);

示例解讀:

??所有的彈窗都是在子組件中的

  1. 首次加載:Initial render、constructor、componentWillMount、render、componentDidMount
  2. 改變父的state:componentWillReceiveProps、shouldComponentUpdate、componentWillUpdate、render、componentDidUpdate
  3. 改變子的state:shouldComponentUpdate、componentWillUpdate、render、componentDidUpdate
  4. 父forceUpdate:componentWillReceiveProps、shouldComponentUpdate、componentWillUpdate、render、componentDidUpdate(和2一樣)
  5. 子forceUpdate:componentWillUpdate、render、componentDidUpdate
  6. 卸載父:componentWillUnmount


本系列文章轉自http://me.molinblog.com/,感謝作者。
http://me.molinblog.com/blog/developing-a-react-edge-1.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/286796.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/286796.shtml
英文地址,請注明出處:http://en.pswp.cn/news/286796.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Android之提示This version of Android Studio cannot open this project, please retry with Android Studio

1 問題 編譯項目&#xff0c;錯誤提示如下 This version of Android Studio cannot open this project, please retry with Android Studio 2 解決辦法 很明顯&#xff0c;看英語翻譯也知道&#xff0c;是由于AS版本太低導致&#xff0c;升級AS就可以了。

Netflix 的 API 架構演變歷程

Netflix 以其松耦合和高度可擴展的微服務架構而聞名&#xff0c;Netflix API 的后端架構經歷了 4 個主要階段。&#x1d40c;&#x1d428;&#x1d427;&#x1d428;&#x1d425;&#x1d422;&#x1d42d;&#x1d421; &#x1d40c;&#x1d428;&#x1d427;&#x1d…

五、Web App 基礎可視組件屬性(IVX 快速開發教程)

五、基礎可視組件屬性 在 iVX 中各個組件存在不同的屬性&#xff0c;這些屬性用于設置顯示的樣式或者是自身具備的特征等&#xff0c;通過更改這些屬性可以極大的方便我們進行項目的創作。 大多數組件都擁有相同的屬性&#xff0c;相同屬性在以下內容中不會贅述介紹&#xff…

【專升本計算機】甘肅省專升本考試計算機熱點考點(填空題115道)

甘肅專升本考試計算機填空題熱點考點 1 、自計算機問世至今已經經歷了四個時代,劃分時代的主要依據是計算機的構成元件。 2 、世界上第一臺電子數字計算機采用的邏輯元件是電子管。 3 、早期的計算機體積大、耗能高、速度慢,其主要原因是制約于元器件。 4 、當前的計算機一…

【回溯法】競賽游戲

題目描述 某游戲規則中&#xff0c;甲乙雙方戰斗&#xff0c;每一回合總能分出勝負&#xff0c;游戲規定&#xff1a; 1.失敗的一方要將自己體力值的1/4加給勝利的一方。 2.游戲開始時&#xff0c;甲的體力值是1000&#xff0c;乙的體力值是2000。 3.每一回合&#xff0c;甲乙勝…

zabbix自動發現(Discovery)功能使用

隨著監控主機不斷增多&#xff0c;有的時候需要添加一批機器&#xff0c;特別是剛用zabbix的童鞋 需要將公司的所有服務器添加到zabbix&#xff0c;如果使用傳統辦法去單個添加設備、分組、項目、圖像…..結果應該是讓人吐的結果。 鑒于這個問題我們可以好好利用下Zabbix大…

Apache之三種工作模式和配置性能優化

1 Apache的3種模式和版本 Apache目前一共有三種穩定的MPM&#xff08;Multi-Processing Module&#xff0c;多進程處理模塊&#xff09;模式&#xff0c;它們分別是prefork&#xff0c;worker和event。 我們可以使用httpd -V 命令查看apache的版本和模式&#xff0c;如果你服務…

lsof命令

lsof, LiSt Opened Files, 列出打開的文件, 聽起來很簡單的樣子. 但想*nix中很多其他工具一樣, lsof把這件簡單的事情做到了爐火純青. 因為Unix認為”一切皆文件”, 那么”打開的文件”就不僅僅是傳統意義上打開的文件了, 還可以是網絡/Unix域套接字, 匿名/具名管道, 共享庫文件…

React-引領未來的用戶界面開發框架-讀書筆記(二)

第4章 數據流 由于react的數據流向是單向的&#xff08;其父節點傳遞到子節點&#xff09;&#xff0c; 因此組件是簡單且易于把握的&#xff08;它們只需要從父節點獲取props渲染即可&#xff09; 假如頂層組件的某個prop改變了&#xff0c;react會遞歸地向下遍歷整個組件樹&a…

六、WebApp 二手信息站點頁面制作(IVX 快速開發教程)

六、二手信息站點頁面制作 在了解了基礎可視組件后&#xff0c;我們可以通過這些可視組件進行站點頁面開發&#xff0c;在此以一個二手交易網站站點頁面為例&#xff0c;本教程示例并不是成熟完善的示例&#xff0c;需要各位讀者進行少量完善&#xff0c;示例只是用于功能講解…

【專升本計算機】甘肅省專升本考試公共課計算機填空題考點匯總

甘肅專升本考試公共課計算機填空題考點匯總 Excel 工作簿文件的默認擴展名為 xls 。 Excel 主界面窗口中編輯欄上的 “fx” 按鈕用來向單元格插入函數。 用來給電子工作表中的行號進行編號的是數字。 在 Excel 中,輸入數字作為文本使用時,需要輸入作為先導標記的字符是單引…

Blazor University (25)路由 —— 通過 HTML 導航

原文鏈接&#xff1a;https://blazor-university.com/routing/navigating-our-app-via-html/通過 HTML 導航源代碼[1]鏈接到 Blazor 組件中的路由的最簡單方法是使用 HTML 超鏈接。<a href"/Counter">This works just fine</a>Blazor 組件中的超鏈接會被…

css3選擇器詳解

css3選擇器詳解css中除了早先最早的&#xff0c;ID選擇器&#xff0c;class選擇器一些以外在css3中新加入了新的選擇器&#xff0c;新選擇器的使用大大的方便了我們的編程&#xff0c;下面我就說一些css3的選擇器的使用方法&#xff0c; p 選擇了所有<p>元素的標簽…

OpenReports中文支持方案

此文章在《OpenReports中文支持完全解決方案.doc》的基礎上做優化&#xff0c;并貼出代碼。已測試通過。 一、主要解決的問題 1 頁面顯示支持中文 2 與服務器或數據庫的交互支持中文 3 查詢結果支持中文 4 導出文件名及內容支持中文 二、解決方案及方法 1 …

LeetCode之First Unique Character in a String

1、題目 Given a string, find the first non-repeating character in it and return its index. If it doesnt exist, return -1. Examples: s "leetcode" return 0.s "loveleetcode", return 2. 2、代碼實現 public class Solution {public int firstU…

七、功能性組件與事件邏輯(IVX 快速開發教程)

七、功能性組件與事件邏輯 由于 iVX 極度易用的特性&#xff0c;在 iVX 中開發微信小程序、WebApp、小游戲應用的開發流程大致相同。介紹完基礎可視化組件后通過后臺的服務、數據庫與事件結合即可完成一個應用的開發&#xff1b;此篇將會介紹 iVX 功能性組件與事件&#xff0c…

python assert的作用

一、python assert的作用&#xff1a; 根據Python 官方文檔解釋(https://docs.python.org/3/reference/simple_stmts.html#assert), "Assert statements are a convenient way to insert debugging assertions into a program". 二、一般的用法是&#xff1a; assert…

React-引領未來的用戶界面開發框架-讀書筆記(三)

第8章 DOM操作 多數情況下&#xff0c;React的虛擬DOM足以用來創建你想要的用戶體驗&#xff0c;而根本不需要直接操作底層真實的DOM。然而也有一些例外。最常見的場景包括&#xff1a;需要與一個沒有使用React的第三方類庫進行整合&#xff0c;或者執行一個React沒有原生支持的…

【專升本計算機】甘肅省普通高等學校專升本考試計算機全真模擬試卷(一)

甘肅省普通高等學校專升本考試計算機全真模擬試卷(一) 一、單項選擇題(在每小題給出的四個選項中只有一項是正確的,將正確選項的字母序號填在括號內。每小題1分,共60分。) 1.在Excel中,當單元格中出現#N/A時,表示( )。 A.公式中有Excel不能識別的文本 B.公式或函數…

WPF 基礎控件之 ToggleButton 樣式

其他基礎控件1.Window2.Button3.CheckBox4.ComboBox5.DataGrid 6.DatePicker7.Expander8.GroupBox9.ListBox10.ListView11.Menu12.PasswordBox13.TextBox14.RadioButtonToggleButton 實現下面的效果1&#xff09;ToggleButton來實現動畫&#xff1b;Border嵌套 Ellipse并設置T…