(React 框架)React技术
1、簡介??
React 是Facebook 開發并開源的前端框架
當時他們的團隊在市面上沒找到合適的MVC 框架,就自己寫一個 JS 框架,用來架設 instagram(圖片分享社交網路),2013年開源
React 解決的是前端MVC 框架中的view 視圖層的問題。
2、Virual DOM
DOM(文檔對象模型Document Object Model)
將網頁內所有內容映射到一顆樹形結構的層級對象模型上,瀏覽器提供對DOM的支持,用戶可以是用腳本調用DOM API 來動態的修改DOM 結點,從而達到修改網頁的目的,這種修改是瀏覽器中完成的,瀏覽器會根據DOM 的改變重繪 改變DOM 結點部分。
修改DOM 重新渲染代價太高,前端框架為了提高效率,盡量減少DOM 的重繪,提出了Virtual DOM,所有的修改都是在現在的Cirtual DOM 上完成的,通過比較算法,找出瀏覽器DOM 之間的差異,使用這個差操作DOM,瀏覽器只需要渲染這部分變化就行了
React 實現了DOM Diff 算法,可以高效的對比Virtual DOM 和DOM 之間的差異。
3、支持JSX 語法
jsx 是 一種JavaScript 和XML 混寫的語法,是JavaScript的擴展
XML?被設計為傳輸和存儲數據,其焦點是數據的內容。 HTML 被設計用來顯示數據,其焦點是數據的外觀
4、測試程序
修改 /src/index.js:
修改 根目錄下的 index.html:在html文件中,提供一個div標簽,同時提供id ,使得react可以通過id找到
啟動 npm start 后
? ?
程序解釋:
import React from "react";? 導入 react 模塊
import ReactDom? from "react-dom";導入react 的DOM 模塊
class Root extends React.Component :組件類定義,從React.Component 類上繼承,這個類生成JSXElement對象即React元素。
render()渲染函數,返回組件中渲染的內容,注意,只能返回唯一一個頂級元素回去
ReactDom.render(<Root/>, document.getElementById("root")):第一個參數是JSXElement對象,第二個是DOM的Element元素,將React元素添加到DOM的Element 元素中并渲染。 也可以使用name,如果Element元素的屬性定義了name,document.getElementsByName("newroot")
(不推薦使用)還可以使用React.createElement創建react元素,第一參數是react組件或者一個HTML的標簽明后才能(如:div,span)
?
增加一個子元素: (這就是SPA網頁,單頁應用,普通的爬蟲就只能爬基本頁面了,因為此時,css和js分割開了) 圖二是 DOM數,虛擬DOM 是react的事
? ??
注意:
? JSX 規范:
-
-
- 約定標簽中首字符小寫就是html標記,首字母大寫就是組件
- 要求嚴格的HTML標記,要求所有標簽都必須是閉合的,br也應該寫成<br /> ,/ 前留一個空格
- 單行省略小括號,多行使用小括號
- 元素有嵌套,建議多行,注意縮進
- JSX表達式:表達式使用{ } 括起來,如果大括號內使用了引號,會當做字符串處理,例如 <div>{'2>1?true:fase'}</div>
-
?
5、組件狀態 state?
每一個 React組件 都有一個狀態屬性 state,它是一個JavaScript對象,可以為他定義屬性來保存值
如果狀態變化了,會觸發UI 的重新渲染,使用setState()方法可以修改stste值
注意:state是每個組件自己內部使用的,是組件自己的屬性
依然修改/src/index.js
解決方式1:
??
? 可以使用延時函數,setTimeout(()=> this.setState({ p1: ' jerry' }), 3000)? 是一個異步函數
但是 不要這樣使用,把setState放在別的地方
setInterval() 每幾秒,執行一次,而 setTimeout 多少秒后,執行一次復雜狀態的例子
瀏覽器結果:
? ?========》點擊后
?
div的id 是t1 ,鼠標按下事件捆綁了一個函數,只要鼠標按下就出觸發調用 getEventTrigger 函數,瀏覽器會送給他一個參數 event, event是事件對象,當事件觸發時,event 包含觸發這個時間的對象
?
HTML DOM的JavaScript 事件
使用React 實現上面的傳統的HTML
?
分析:
Toggle類
它有自己的state屬性
當render完成后,網頁上有一個div標簽,div標簽對象捆綁了一個click 時間的處理函數,div標簽內有文本內容
如果通過點擊左鍵,即觸發了一個click方法關聯的handleClick 函數,在這個函數里將狀態改變
狀態值state,的改變 將引發render重繪
如果組件自己的state變了,只會觸發自己的render方法重繪。
注意:
{this.handleClick.bind(this)} 不能外加括號
this.handleClick.bind(this) 一定要綁定this,否則當觸發捆綁的函數時,this是函數執行的上下文決定的,this已經不是觸發事件的對象了。
console.log(event.target.id) 取回的產生的對象的id,但是這不是我們封裝的組件對象,所以
console.log(event.target ===this) 是false,所以這里一定要使用this,而這個this是通過綁定來的
event.target 就是生成的一個塊 <div>-----</div>
React中的事件:
使用小駝峰
使用JSX表達式,表達式中指定事件處理函數
不能使用return false 如果要組織事件默認行為,使用event。preventDefault()
6、屬性props:
props 就是組件的屬性properties。
把React組件當作標簽使用,可以為其增加屬性,如下:
<Toggle name="school" parent={this} />
為上面的Toggle 元素增加屬性:
嘗試修改props 的屬性值,會拋出 TypeError:cannot assign to read only property “name” of object # <Object>異常
應該說, state是私有 private 的屬于組件自己的屬性,組件外無法直接訪問,可以修改state但是建議使用setState方法
props是公有public屬性組件外也可以訪問,但是只讀。
7、構造器constructor:
使用ES 6 的構造器,要提供一個參數props, 并把這個參數使用super傳遞給父類
??
8、組件的生命周期:
組件的生命周期可分為三個狀態
-
- Mounting :已 插入真實的DOM
- Updating:正在被重新渲染
- Unmounting:已移出真實的DOM
組件的生命周期狀態,說明在不同時機訪問 組件,組件正在處于生命周期的不同轉臺上
在不同的生命周期狀態訪問,就產生不同的方法。
-
- 裝載組件觸發
- componentWillMOunt 在渲染前調用, 在客戶端---也在服務端。只會在裝載之前調用一次。
- componentDidMount 在第一次渲染后調用,只在客戶端,之后組件已經生成了對應的DOM 結構可以通過this.getDOMNode()來進行訪問,如果你想和其他JS 框架一起使用,可以在這個方法中調用setTimeout,setInterval或者發送AJAX 請求等操作(防止異步操作阻塞UI),只在裝載完成后調用一次,在render之后
- 更新組件觸發,這些方法不會再首次render組件的周期調用
- componentWillReceiveProps(nextProps)在組件接收到一個新的prop的時候,調用,這個方法在初始化render時不會被調用
- shouldComponentUpdate(nextProps,nextState)返回一個布爾值,組件接收到新的props或者state時被調用,在初始化時或者使用forceUpdate時不會被調用
- 可以在你確認不需要更新組件時 使用
- 如果設置為false,就是不允許更新組件,那么componentWillUpdate,componentDidupdate不會執行
- componentWillUpdate(nextProps, nextState) 在組件接收到新的props或者state但還沒有render時被調用,在初始化時不會被調用
- componentDidUpdate(prevProps,prevState)在組件完成更新后立即被調用,在初始化時不會被調用
- 卸載組件觸發
- componentWillUnmount 在組件從DOM中移除的時候,立即被調用
- 裝載組件觸發
有圖可知:
constructor 構造器是最早執行的函數
觸發更新生命周期函數,需要更新 state 或 props
因此,重寫編寫 /scr/index.js
構造兩個組件,在子組件SUb中,加入所有生命周期函數
測試:裝載,卸載組件的生命周期函數。
1 import React from 'react'; 2 import ReactDom from 'react-dom'; 3 4 5 class Sub extends React.Component { 6 constructor (props){ 7 console.log("sub constructor") 8 super(props); 9 this.state = {count:0}; 10 } 11 handleClick(event) { 12 this.setState({count:this.state.count + 1}); 13 } 14 render() { 15 console.log('sub render'); 16 return ( 17 <div id="sub" onClick={this.handleClick.bind(this)}> 18 Sub's count = {this.state.count} 19 </div> 20 ); 21 } 22 23 componentWillMount() { 24 console.log('sub componentwillmont') 25 } 26 27 componentDidMount() { 28 console.log('sub componentdidmount') 29 } 30 componentWillUnmount(){ 31 console.log('sub componentdidunmount') 32 } 33 34 35 } 36 37 38 class Root extends React.Component{ 39 constructor (props) { 40 console.log("root constructor") 41 super(props); 42 this.state = {}; 43 44 } 45 render (){ 46 return( 47 <div> 48 <Sub /> 49 </div> 50 ) 51 } 52 } 53 54 ReactDom.render(<Root/>, document.getElementById("newroot"));?
? 結果:
? ? ? ? ?
?
? 增加,更新組件函數:
演示 props的改變,為Root增加一個click事件處理函數
1 import React from 'react'; 2 import ReactDom from 'react-dom'; 3 import { runInAction } from 'mobx'; 4 5 6 class Sub extends React.Component { 7 constructor (props){ 8 console.log("sub constructor") 9 super(props); 10 this.state = {count:0}; 11 } 12 handleClick(event) { 13 this.setState({count:this.state.count + 1}); 14 } 15 render() { 16 console.log('sub render'); 17 return ( 18 <div style={{height:200 + "px", color:'red', backgroundColor:"#aaffff"}}> 19 <a id='sub' onClick={this.handleClick.bind(this)}> 20 sub'x count = {this.state.cont} 21 </a> 22 </div> 23 ); 24 } 25 26 componentWillMount() { 27 //constructor 之后,第一次render之前 28 console.log('sub componentwillmont') 29 } 30 31 componentDidMount() { 32 // 第一次render之前 33 console.log('sub componentdidmount') 34 } 35 componentWillUnmount(){ 36 //清理工作 37 console.log('sub componentdidunmount') 38 } 39 40 componentWillReceiveProps(nexProps) { 41 // props更新時,街道新的props,交給shouldComponentUpdate 42 // props組件內只讀,只能從外部改變 43 console.log(this.props) 44 console.log(nexProps) 45 console.log('sub com---receiveProps', this.state.count) 46 } 47 48 shouldComponentUpdate(nexProps, nextState) { 49 // 是否組件更新,props 或state 方式改變,返回布爾值,true才會更新 50 console.log('sub shuold--------', this.state.count, nextState) 51 return true 52 53 } 54 55 componentWillUpdate(nexProps, nextState) { 56 //同意更新后,真正更新前,之后調用rener 57 console.log('will update', this.state.count, nextState) 58 } 59 60 componentDidUpdate(prevProps, prevState){ 61 //同意更新后,真正更新后,在render在之后調用 62 console.log('did Update', this.state.count, prevState) 63 } 64 65 } 66 67 68 class Root extends React.Component{ 69 constructor (props) { 70 console.log("root constructor") 71 super(props); 72 this.state = {flag:true, name:'root'}; 73 74 } 75 handleClick(event){ 76 this.setState({ 77 flag:!this.state.flag, 78 name:this.state.flag ? this.state.name.toLowerCase() : this.state.name.toUpperCase() 79 }) 80 } 81 render (){ 82 return( 83 <div id='t1' onClick={this.handleClick.bind(this)}> 84 my name is {this.state.name} 85 <Sub /> {/* 父組件的render,會引起下一級組件的更新流程,導致props重新發送,即使子組件props沒有改變*/} 86 </div> 87 ) 88 } 89 } 90 91 ReactDom.render(<Root/>, document.getElementById("newroot"));?
? componentWillMount 第一次裝載,在首次render之前,例如控制state,props
conpinentDidMount 第一次裝載結束,在首次render之后,
?
?
?
?
?
?
?
?
注:++ 原位置自動加1 ,+= 是調到棧里,加1 再返回
?
?
?
?10、無狀態組件
? React從15.0 開始支持無狀態組件,定義如下:
? 無狀態組件,也叫函數式組件
? 開發中,很多情況下,組件其實很簡單,不需要state狀態,也不需要使用生命周期函數,無狀態組件很好的滿足了需要
無狀態組件函數應該提供一個參數props,返回一個React元素
無狀態組件函數本身就是 render函數
? 改寫上面的代碼:箭頭函數
?
?11、高階組件
?
? 如果要在上例的Root組件進行增強怎么辦,例如將Root 組件的div 外部在加入其它的 div
簡化Wrapper?
?
1 import React from 'react'; 2 import ReactDom from 'react-dom'; 3 // let Wrapper = function (Component/*傳入組件*/, props) { 4 // return ( 5 // <div> 6 // {props.schoolName} 7 // <hr /> 8 // <Component /> 9 // </div> 10 // ) 11 // } 12 // 柯里化 13 let Wrapper = function (Component) { 14 function _wrapper(props) { 15 return ( 16 <div> 17 {props.schoolName} 18 <hr /> 19 <Component /> 20 </div>) 21 } 22 return _wrapper 23 } 24 // 第一次簡化 25 let Wrapper = function(Component) { 26 return function _wrapper(props){ 27 return ( 28 <div> 29 {props.schoolName} 30 <hr /> 31 <Component /> 32 </div>) 33 } 34 } 35 //第二次簡化 36 let Wrapper = function(Component) { 37 return (props) => { 38 return ( 39 <div> 40 {props.schoolName} 41 <hr /> 42 <Component /> 43 </div>) 44 } 45 } 46 // 第三次簡化 47 let Wrapper = (Component) =>(props) => 48 ( 49 <div> 50 {props.schoolName} 51 <hr /> 52 <Component /> 53 </div> 54 ) 55 56 //整理 57 let Wrapper = (Component) =>(props) => <div> {props.schoolName} <hr /> <Component /> </div> 58 71 let Root = (props) => <div>Root</div> 72 73 // 返回新組件 74 let NewComp = Wrapper(Root) 75 ReactDom.render(<NewComp schoolName="jerry"/>, document.getElementById('newroot'))? 測試:加入子組件(無狀態組件)
?
?12、裝飾器
? 新版的ES2016中增加了裝飾器的支持,因此可以使用裝飾器來改造上面的代碼。
裝飾器是裝飾函數,類,不能對一個變量裝飾(這樣是不對的)
?
? ES 2016 的裝飾器只能裝飾類,所以,將Root改寫成類
?
? 讓Root 也顯示schoolName
?
13、帶參裝飾器
? 想給裝飾器函數增加一個id 參數
1 import React from 'react'; 2 import ReactDom from 'react-dom'; 3 4 let Wrapper = (id, Component) =>(props) => 5 ( 6 <div id={id}> 7 {props.schoolName} 8 <hr /> 9 <Component /> 10 </div> 11 ) 12 13 // 柯里化 14 let Wrapper = id => Component => (props) => 15 ( 16 <div id={id}> 17 {props.schoolName} 18 <hr /> 19 <Component {...props}/> 20 </div> 21 ) 22 23 24 @Wrapper('123') // Root = wrapper("123")(Root) = (props) => ..... 25 26 class Root extends React.Component { 27 render(){ 28 return <div>Root ---- {this.props.address}</div> 29 } 30 } 31 32 ReactDom.render(<Root schoolName="jerry" address="somewhere"/>, document.getElementById('newroot'))?
?
?
?
?
?
?
?
?
?
轉載于:https://www.cnblogs.com/JerryZao/p/9986008.html
總結
以上是生活随笔為你收集整理的(React 框架)React技术的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: day13-(事务mvc反射补充)
- 下一篇: Apache RocketMQ在linu