日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

React入门看这篇就够了

發(fā)布時(shí)間:2025/6/17 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 React入门看这篇就够了 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>

摘要: 很多值得了解的細(xì)節(jié)。

  • 原文:React入門看這篇就夠了
  • 作者:Random

Fundebug經(jīng)授權(quán)轉(zhuǎn)載,版權(quán)歸原作者所有。

React 背景介紹

  • React 入門實(shí)例教程

React 起源于 Facebook 的內(nèi)部項(xiàng)目,因?yàn)樵摴緦?duì)市場(chǎng)上所有 JavaScript MVC 框架,都不滿意,就決定自己寫一套,用來(lái)架設(shè) Instagram 的網(wǎng)站。做出來(lái)以后,發(fā)現(xiàn)這套東西很好用,就在2013年5月開源了。

什么是React

  • A JAVASCRIPT LIBRARY FOR BUILDING USER INTERFACES
    • 用來(lái)構(gòu)建UI的 JavaScript庫(kù)
    • React 不是一個(gè) MVC 框架,僅僅是視圖(V)層的庫(kù)
  • React 官網(wǎng)
  • React 中文文檔

特點(diǎn)

  • 使用 JSX語(yǔ)法 創(chuàng)建組件,實(shí)現(xiàn)組件化開發(fā),為函數(shù)式的 UI 編程方式打開了大門
  • 性能高的讓人稱贊:通過(guò) diff算法 和 虛擬DOM 實(shí)現(xiàn)視圖的高效更新
  • HTML僅僅是個(gè)開始
> JSX --TO--> EveryThing- JSX --> HTML - JSX --> native ios或android中的組件(XML) - JSX --> VR - JSX --> 物聯(lián)網(wǎng)

為什么要用React

  • 使用組件化開發(fā)方式,符合現(xiàn)代Web開發(fā)的趨勢(shì)
  • 技術(shù)成熟,社區(qū)完善,配件齊全,適用于大型Web項(xiàng)目(生態(tài)系統(tǒng)健全)
  • 由Facebook專門的團(tuán)隊(duì)維護(hù),技術(shù)支持可靠
  • ReactNative - Learn once, write anywhere: Build mobile apps with React
  • 使用方式簡(jiǎn)單,性能非常高,支持服務(wù)端渲染
  • React非常火,從技術(shù)角度,可以滿足好奇心,提高技術(shù)水平;從職業(yè)角度,有利于求職和晉升,有利于參與潛力大的項(xiàng)目

React中的核心概念

  • 虛擬DOM(Virtual DOM)
  • Diff算法(虛擬DOM的加速器,提升React性能的法寶)

虛擬DOM(Vitural DOM)

React將DOM抽象為虛擬DOM,虛擬DOM其實(shí)就是用一個(gè)對(duì)象來(lái)描述DOM,通過(guò)對(duì)比前后兩個(gè)對(duì)象的差異,最終只把變化的部分重新渲染,提高渲染的效率

為什么用虛擬dom,當(dāng)dom反生更改時(shí)需要遍歷 而原生dom可遍歷屬性多大231個(gè) 且大部分與渲染無(wú)關(guān) 更新頁(yè)面代價(jià)太大

  • 如何實(shí)現(xiàn)一個(gè) Virtual DOM 算法
  • 理解 Virtual DOM

VituralDOM的處理方式

  • 用 JavaScript 對(duì)象結(jié)構(gòu)表示 DOM 樹的結(jié)構(gòu),然后用這個(gè)樹構(gòu)建一個(gè)真正的 DOM 樹,插到文檔當(dāng)中
  • 當(dāng)狀態(tài)變更的時(shí)候,重新構(gòu)造一棵新的對(duì)象樹。然后用新的樹和舊的樹進(jìn)行比較,記錄兩棵樹差異
  • 把2所記錄的差異應(yīng)用到步驟1所構(gòu)建的真正的DOM樹上,視圖就更新了
  • Diff算法

    • Reconciliation diff
    • diff算法 - 中文文檔
    • 不可思議的 react diff
    • React diff 算法

    當(dāng)你使用React的時(shí)候,在某個(gè)時(shí)間點(diǎn) render() 函數(shù)創(chuàng)建了一棵React元素樹, 在下一個(gè)state或者props更新的時(shí)候,render() 函數(shù)將創(chuàng)建一棵新的React元素樹, React將對(duì)比這兩棵樹的不同之處,計(jì)算出如何高效的更新UI(只更新變化的地方)

    有一些解決將一棵樹轉(zhuǎn)換為另一棵樹的最小操作數(shù)算法問(wèn)題的通用方案。然而,樹中元素個(gè)數(shù)為n,最先進(jìn)的算法 的時(shí)間復(fù)雜度為O(n3) 。

    如果直接使用這個(gè)算法,在React中展示1000個(gè)元素則需要進(jìn)行10億次的比較。這操作太過(guò)昂貴,相反,React基于兩點(diǎn)假設(shè),實(shí)現(xiàn)了一個(gè)O(n)算法,提升性能:

    React中有兩種假定:

    • 兩個(gè)不同類型的元素會(huì)產(chǎn)生不同的樹(根元素不同結(jié)構(gòu)樹一定不同)
    • 開發(fā)者可以通過(guò)key屬性指定不同樹中沒有發(fā)生改變的子元素

    Diff算法的說(shuō)明 - 1

    • 如果兩棵樹的根元素類型不同,React會(huì)銷毀舊樹,創(chuàng)建新樹
    // 舊樹 <div><Counter /> </div>// 新樹 <span><Counter /> </span>執(zhí)行過(guò)程:destory Counter -> insert Counter

    Diff算法的說(shuō)明 - 2

    • 對(duì)于類型相同的React DOM 元素,React會(huì)對(duì)比兩者的屬性是否相同,只更新不同的屬性
    • 當(dāng)處理完這個(gè)DOM節(jié)點(diǎn),React就會(huì)遞歸處理子節(jié)點(diǎn)。
    // 舊 <div className="before" title="stuff" /> // 新 <div className="after" title="stuff" /> 只更新:className 屬性// 舊 <div style={{color: 'red', fontWeight: 'bold'}} /> // 新 <div style={{color: 'green', fontWeight: 'bold'}} /> 只更新:color屬性

    Diff算法的說(shuō)明 - 3

    • 1 當(dāng)在子節(jié)點(diǎn)的后面添加一個(gè)節(jié)點(diǎn),這時(shí)候兩棵樹的轉(zhuǎn)化工作執(zhí)行的很好
    // 舊 <ul><li>first</li><li>second</li> </ul>// 新 <ul><li>first</li><li>second</li><li>third</li> </ul>執(zhí)行過(guò)程: React會(huì)匹配新舊兩個(gè)<li>first</li>,匹配兩個(gè)<li>second</li>,然后添加 <li>third</li> tree
    • 2 但是如果你在開始位置插入一個(gè)元素,那么問(wèn)題就來(lái)了:
    // 舊 <ul><li>Duke</li><li>Villanova</li> </ul>// 新 <ul><li>Connecticut</li><li>Duke</li><li>Villanova</li> </ul>在沒有key屬性時(shí)執(zhí)行過(guò)程: React將改變每一個(gè)子刪除重新創(chuàng)建,而非保持 <li>Duke</li> 和 <li>Villanova</li> 不變

    key 屬性

    為了解決以上問(wèn)題,React提供了一個(gè) key 屬性。當(dāng)子節(jié)點(diǎn)帶有key屬性,React會(huì)通過(guò)key來(lái)匹配原始樹和后來(lái)的樹。

    // 舊 <ul><li key="2015">Duke</li><li key="2016">Villanova</li> </ul>// 新 <ul><li key="2014">Connecticut</li><li key="2015">Duke</li><li key="2016">Villanova</li> </ul> 執(zhí)行過(guò)程: 現(xiàn)在 React 知道帶有key '2014' 的元素是新的,對(duì)于 '2015' 和 '2016' 僅僅移動(dòng)位置即可
    • 說(shuō)明:key屬性在React內(nèi)部使用,但不會(huì)傳遞給你的組件
    • 推薦:在遍歷數(shù)據(jù)時(shí),推薦在組件中使用 key 屬性:<li key={item.id}>{item.name}</li>
    • 注意:key只需要保持與他的兄弟節(jié)點(diǎn)唯一即可,不需要全局唯一
    • 注意:盡可能的減少數(shù)組index作為key,數(shù)組中插入元素的等操作時(shí),會(huì)使得效率底下

    React的基本使用

    • 安裝:npm i -S react react-dom
    • react:react 是React庫(kù)的入口點(diǎn)
    • react-dom:提供了針對(duì)DOM的方法,比如:把創(chuàng)建的虛擬DOM,渲染到頁(yè)面上
    // 1. 導(dǎo)入 react import React from 'react' import ReactDOM from 'react-dom'// 2. 創(chuàng)建 虛擬DOM // 參數(shù)1:元素名稱 參數(shù)2:元素屬性對(duì)象(null表示無(wú)) 參數(shù)3:當(dāng)前元素的子元素string||createElement() 的返回值 const divVD = React.createElement('div', {title: 'hello react' }, 'Hello React!!!')// 3. 渲染 // 參數(shù)1:虛擬dom對(duì)象 參數(shù)2:dom對(duì)象表示渲染到哪個(gè)元素內(nèi) 參數(shù)3:回調(diào)函數(shù) ReactDOM.render(divVD, document.getElementById('app'))

    createElement()的問(wèn)題

    • 說(shuō)明:createElement()方式,代碼編寫不友好,太復(fù)雜
    var dv = React.createElement("div",{ className: "shopping-list" },React.createElement("h1",null,"Shopping List for "),React.createElement("ul",null,React.createElement("li",null,"Instagram"),React.createElement("li",null,"WhatsApp")) ) // 渲染 ReactDOM.render(dv, document.getElementById('app'))

    JSX 的基本使用

    • 注意:JSX語(yǔ)法,最終會(huì)被編譯為 createElement() 方法
    • 推薦:使用 JSX 的方式創(chuàng)建組件
    • JSX - JavaScript XML
    • 安裝:npm i -D babel-preset-react (依賴與:babel-core/babel-loader)

    注意:JSX的語(yǔ)法需要通過(guò) babel-preset-react 編譯后,才能被解析執(zhí)行

    /* 1 在 .babelrc 開啟babel對(duì) JSX 的轉(zhuǎn)換 */ {"presets": ["env", "react"] }/* 2 webpack.config.js */ module: [rules: [{ test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ },] ]/* 3 在 js 文件中 使用 JSX */ const dv = (<div title="標(biāo)題" className="cls container">Hello JSX!</div> )/* 4 渲染 JSX 到頁(yè)面中 */ ReactDOM.render(dv, document.getElementById('app'))

    JSX的注意點(diǎn)

    • 如果在 JSX 中給元素添加類, 需要使用 className 代替 class
      • 類似:label 的 for屬性,使用htmlFor代替
    • 在 JSX 中可以直接使用 JS代碼,直接在 JSX 中通過(guò) {} 中間寫 JS代碼即可
    • 在 JSX 中只能使用表達(dá)式,但是不能出現(xiàn) 語(yǔ)句!!!
    • 在 JSX 中注釋語(yǔ)法:{/* 中間是注釋的內(nèi)容 */}

    React組件

    React 組件可以讓你把UI分割為獨(dú)立、可復(fù)用的片段,并將每一片段視為相互獨(dú)立的部分。

    • 組件是由一個(gè)個(gè)的HTML元素組成的
    • 概念上來(lái)講, 組件就像JS中的函數(shù)。它們接受用戶輸入(props),并且返回一個(gè)React對(duì)象,用來(lái)描述展示在頁(yè)面中的內(nèi)容

    React創(chuàng)建組件的兩種方式

    • 通過(guò) JS函數(shù) 創(chuàng)建(無(wú)狀態(tài)組件)
    • 通過(guò) class 創(chuàng)建(有狀態(tài)組件)

    函數(shù)式組件 和 class 組件的使用場(chǎng)景說(shuō)明:

    • 如果一個(gè)組件僅僅是為了展示數(shù)據(jù),那么此時(shí)就可以使用 函數(shù)組件
    • 如果一個(gè)組件中有一定業(yè)務(wù)邏輯,需要操作數(shù)據(jù),那么就需要使用 class 創(chuàng)建組件,因?yàn)?#xff0c;此時(shí)需要使用 state

    JavaScript函數(shù)創(chuàng)建組件

    • 注意:1 函數(shù)名稱必須為大寫字母開頭,React通過(guò)這個(gè)特點(diǎn)來(lái)判斷是不是一個(gè)組件
    • 注意:2 函數(shù)必須有返回值,返回值可以是:JSX對(duì)象或null
    • 注意:3 返回的JSX,必須有一個(gè)根元素
    • 注意:4 組件的返回值使用()包裹,避免換行問(wèn)題
    function Welcome(props) {return (// 此處注釋的寫法 <div className="shopping-list">{/* 此處 注釋的寫法 必須要{}包裹 */}<h1>Shopping List for {props.name}</h1><ul><li>Instagram</li><li>WhatsApp</li></ul></div>) }ReactDOM.render(<Welcome name="jack" />,document.getElementById('app') )

    class創(chuàng)建組件

    在es6中class僅僅是一個(gè)語(yǔ)法糖,不是真正的類,本質(zhì)上還是構(gòu)造函數(shù)+原型 實(shí)現(xiàn)繼承

    // ES6中class關(guān)鍵字的簡(jiǎn)單使用// - **ES6中的所有的代碼都是運(yùn)行在嚴(yán)格模式中的** // - 1 它是用來(lái)定義類的,是ES6中實(shí)現(xiàn)面向?qū)ο缶幊痰男路绞?// - 2 使用`static`關(guān)鍵字定義靜態(tài)屬性 // - 3 使用`constructor`構(gòu)造函數(shù),創(chuàng)建實(shí)例屬性 // - [參考](http://es6.ruanyifeng.com/#docs/class)// 語(yǔ)法: class Person {// 實(shí)例的構(gòu)造函數(shù) constructorconstructor(age){// 實(shí)例屬性this.age = age}// 在class中定義方法 此處為實(shí)例方法 通過(guò)實(shí)例打點(diǎn)調(diào)用sayHello () {console.log('大家好,我今年' + this.age + '了');}// 靜態(tài)方法 通過(guò)構(gòu)造函數(shù)打點(diǎn)調(diào)用 Person.doudou()static doudou () {console.log('我是小明,我新get了一個(gè)技能,會(huì)暖床');} } // 添加靜態(tài)屬性 Person.staticName = '靜態(tài)屬性' // 實(shí)例化對(duì)象 const p = new Person(19)// 實(shí)現(xiàn)繼承的方式class American extends Person {constructor() {// 必須調(diào)用super(), super表示父類的構(gòu)造函數(shù)super()this.skin = 'white'this.eyeColor = 'white'} }// 創(chuàng)建react對(duì)象 // 注意:基于 `ES6` 中的class,需要配合 `babel` 將代碼轉(zhuǎn)化為瀏覽器識(shí)別的ES5語(yǔ)法 // 安裝:`npm i -D babel-preset-env`// react對(duì)象繼承字React.Component class ShoppingList extends React.Component {constructor(props) { super(props)}// class創(chuàng)建的組件中 必須有rander方法 且顯示return一個(gè)react對(duì)象或者nullrender() {return (<div className="shopping-list"><h1>Shopping List for {this.props.name}</h1><ul><li>Instagram</li><li>WhatsApp</li></ul></div>)} }

    推薦大家使用Fundebug,一款很好用的BUG監(jiān)控工具~

    給組件傳遞數(shù)據(jù) - 父子組件傳遞數(shù)據(jù)

    • 組件中有一個(gè) 只讀的對(duì)象 叫做 props,無(wú)法給props添加屬性
    • 獲取方式:函數(shù)參數(shù) props
    • 作用:將傳遞給組件的屬性轉(zhuǎn)化為 props 對(duì)象中的屬性
    function Welcome(props){// props ---> { username: 'zs', age: 20 }return (<div><div>Welcome React</div><h3>姓名:{props.username}----年齡是:{props.age}</h3></div>) }// 給 Hello組件 傳遞 props:username 和 age(如果你想要傳遞numb類型是數(shù)據(jù) 就需要向下面這樣) ReactDOM.reander(<Hello username="zs" age={20}></Hello>, ......)

    封裝組件到獨(dú)立的文件中

    // 創(chuàng)建Hello2.js組件文件 // 1. 引入React模塊 // 由于 JSX 編譯后會(huì)調(diào)用 React.createElement 方法,所以在你的 JSX 代碼中必須首先拿到React。 import React from 'react'// 2. 使用function構(gòu)造函數(shù)創(chuàng)建組件 function Hello2(props){return (<div><div>這是Hello2組件</div><h1>這是大大的H1標(biāo)簽,我大,我驕傲!!!</h1><h6>這是小小的h6標(biāo)簽,我小,我傲嬌!!!</h6></div>) } // 3. 導(dǎo)出組件 export default Hello2// app.js中 使用組件: import Hello2 from './components/Hello2'

    props和state

    props

    • 作用:給組件傳遞數(shù)據(jù),一般用在父子組件之間
    • 說(shuō)明:React把傳遞給組件的屬性轉(zhuǎn)化為一個(gè)對(duì)象并交給 props
    • 特點(diǎn):props是只讀的,無(wú)法給props添加或修改屬性
    • props.children:獲取組件的內(nèi)容,比如:
      • <Hello>組件內(nèi)容</Hello> 中的 組件內(nèi)容
    // props 是一個(gè)包含數(shù)據(jù)的對(duì)象參數(shù),不要試圖修改 props 參數(shù) // 返回值:react元素 function Welcome(props) {// 返回的 react元素中必須只有一個(gè)根元素return <div>hello, {props.name}</div> }class Welcome extends React.Component {constructor(props) {super(props)}render() {return <h1>Hello, {this.props.name}</h1>} }

    state

    狀態(tài)即數(shù)據(jù)

    • 作用:用來(lái)給組件提供組件內(nèi)部使用的數(shù)據(jù)
    • 注意:只有通過(guò)class創(chuàng)建的組件才具有狀態(tài)
    • 狀態(tài)是私有的,完全由組件來(lái)控制
    • 不要在 state 中添加 render() 方法中不需要的數(shù)據(jù),會(huì)影響渲染性能!
      • 可以將組件內(nèi)部使用但是不渲染在視圖中的內(nèi)容,直接添加給 this
    • 不要在 render() 方法中調(diào)用 setState() 方法來(lái)修改state的值
      • 但是可以通過(guò) this.state.name = 'rose' 方式設(shè)置state(不推薦!!!!)
    // 例: class Hello extends React.Component {constructor() {// es6繼承必須用super調(diào)用父類的constructorsuper()this.state = {gender: 'male'}}render() {return (<div>性別:{ this.state.gender }</div>)} }

    JSX語(yǔ)法轉(zhuǎn)化過(guò)程

    // 1、JSX const element = (<h1 className="greeting">Hello, world!</h1> )// 2、JSX -> createElement const element = React.createElement('h1',{className: 'greeting'},'Hello, world!' )// React elements: 使用對(duì)象的形式描述頁(yè)面結(jié)構(gòu) // Note: 這是簡(jiǎn)化后的對(duì)象結(jié)構(gòu) const element = {type: 'h1',props: {className: 'greeting',},children: ['Hello, world'] }

    評(píng)論列表案例

    • 鞏固有狀態(tài)組件和無(wú)狀態(tài)組件的使用
    • 兩個(gè)組件:<CommentList></CommentList> 和 <Comment></Comment>
    [{ user: '張三', content: '哈哈,沙發(fā)' },{ user: '張三2', content: '哈哈,板凳' },{ user: '張三3', content: '哈哈,涼席' },{ user: '張三4', content: '哈哈,磚頭' },{ user: '張三5', content: '哈哈,樓下山炮' } ]// 屬性擴(kuò)展 <Comment {...item} key={i}></Comment>

    style樣式

    // 1. 直接寫行內(nèi)樣式: <li style={{border:'1px solid red', fontSize:'12px'}}></li>// 2. 抽離為對(duì)象形式 var styleH3 = {color:'blue'} var styleObj = {liStyle:{border:'1px solid red', fontSize:'12px'},h3Style:{color:'green'} }<li style={styleObj.liStyle}><h3 style={styleObj.h3Style}>評(píng)論內(nèi)容:{props.content}</h3> </li>// 3. 使用樣式表定義樣式: import '../css/comment.css' <p className="pUser">評(píng)論人:{props.user}</p>

    組件的生命周期

    • 簡(jiǎn)單說(shuō):一個(gè)組件從開始到最后消亡所經(jīng)歷的各種狀態(tài),就是一個(gè)組件的生命周期

    組件生命周期函數(shù)的定義:從組件被創(chuàng)建,到組件掛載到頁(yè)面上運(yùn)行,再到頁(yè)面關(guān)閉組件被卸載,這三個(gè)階段總是伴隨著組件各種各樣的事件,那么這些事件,統(tǒng)稱為組件的生命周期函數(shù)!

    • 通過(guò)這個(gè)函數(shù),能夠讓開發(fā)人員的代碼,參與到組件的生命周期中。也就是說(shuō),通過(guò)鉤子函數(shù),就可以控制組件的行為
    • react component
    • React Native 中組件的生命周期
    • React 生命周期的管理藝術(shù)
    • 智能組件和木偶組件

    組件生命周期函數(shù)總覽

    • 組件的生命周期包含三個(gè)階段:創(chuàng)建階段(Mounting)、運(yùn)行和交互階段(Updating)、卸載階段(Unmounting)
    • Mounting:

    constructor() componentWillMount() render() componentDidMount()

    • Updating

    componentWillReceiveProps() shouldComponentUpdate() componentWillUpdate() render() componentDidUpdate()

    • Unmounting

    componentWillUnmount()

    組件生命周期 - 創(chuàng)建階段(Mounting)

    • 特點(diǎn):該階段的函數(shù)只執(zhí)行一次

    constructor()

    • 作用:1 獲取props 2 初始化state
    • 說(shuō)明:通過(guò) constructor() 的參數(shù)props獲取
    • 設(shè)置state和props
    class Greeting extends React.Component {constructor(props) {// 獲取 propssuper(props)// 初始化 statethis.state = {count: props.initCount}} }// 初始化 props // 語(yǔ)法:通過(guò)靜態(tài)屬性 defaultProps 來(lái)初始化props Greeting.defaultProps = {initCount: 0 };

    componentWillMount()

    • 說(shuō)明:組件被掛載到頁(yè)面之前調(diào)用,其在render()之前被調(diào)用,因此在這方法里同步地設(shè)置狀態(tài)將不會(huì)觸發(fā)重渲染
    • 注意:無(wú)法獲取頁(yè)面中的DOM對(duì)象
    • 注意:可以調(diào)用 setState() 方法來(lái)改變狀態(tài)值
    • 用途:發(fā)送ajax請(qǐng)求獲取數(shù)據(jù)
    componentWillMount() {console.warn(document.getElementById('btn')) // nullthis.setState({count: this.state.count + 1}) }

    render()

    • 作用:渲染組件到頁(yè)面中,無(wú)法獲取頁(yè)面中的DOM對(duì)象
    • 注意:不要在render方法中調(diào)用 setState() 方法,否則會(huì)遞歸渲染
      • 原因說(shuō)明:狀態(tài)改變會(huì)重新調(diào)用render(),render()又重新改變狀態(tài)
    render() {console.warn(document.getElementById('btn')) // nullreturn (<div><button id="btn" onClick={this.handleAdd}>打豆豆一次</button>{this.state.count === 4? null: <CounterChild initCount={this.state.count}></CounterChild>}</div>) }

    componentDidMount()

    • 組件已經(jīng)掛載到頁(yè)面中
    • 可以進(jìn)行DOM操作,比如:獲取到組件內(nèi)部的DOM對(duì)象
    • 可以發(fā)送請(qǐng)求獲取數(shù)據(jù)
    • 可以通過(guò) setState() 修改狀態(tài)的值
    • 注意:在這里修改狀態(tài)會(huì)重新渲染
    componentDidMount() {// 此時(shí),就可以獲取到組件內(nèi)部的DOM對(duì)象console.warn('componentDidMount', document.getElementById('btn')) }

    組件生命周期 - 運(yùn)行階段(Updating)

    • 特點(diǎn):該階段的函數(shù)執(zhí)行多次
    • 說(shuō)明:每當(dāng)組件的props或者state改變的時(shí)候,都會(huì)觸發(fā)運(yùn)行階段的函數(shù)

    componentWillReceiveProps()

    • 說(shuō)明:組件接受到新的props前觸發(fā)這個(gè)方法
    • 參數(shù):當(dāng)前組件props值
    • 可以通過(guò) this.props 獲取到上一次的值
    • 使用:若你需要響應(yīng)屬性的改變,可以通過(guò)對(duì)比this.props和nextProps并在該方法中使用this.setState()處理狀態(tài)改變
    • 注意:修改state不會(huì)觸發(fā)該方法
    componentWillReceiveProps(nextProps) {console.warn('componentWillReceiveProps', nextProps) }

    shouldComponentUpdate()

    • 作用:根據(jù)這個(gè)方法的返回值決定是否重新渲染組件,返回true重新渲染,否則不渲染
    • 優(yōu)勢(shì):通過(guò)某個(gè)條件渲染組件,降低組件渲染頻率,提升組件性能
    • 說(shuō)明:如果返回值為false,那么,后續(xù)render()方法不會(huì)被調(diào)用
    • 注意:這個(gè)方法必須返回布爾值!!!
    • 場(chǎng)景:根據(jù)隨機(jī)數(shù)決定是否渲染組件
    // - 參數(shù): // - 第一個(gè)參數(shù):最新屬性對(duì)象 // - 第二個(gè)參數(shù):最新狀態(tài)對(duì)象 shouldComponentUpdate(nextProps, nextState) {console.warn('shouldComponentUpdate', nextProps, nextState)return nextState.count % 2 === 0 }

    componentWillUpdate()

    • 作用:組件將要更新
    • 參數(shù):最新的屬性和狀態(tài)對(duì)象
    • 注意:不能修改狀態(tài) 否則會(huì)循環(huán)渲染
    componentWillUpdate(nextProps, nextState) {console.warn('componentWillUpdate', nextProps, nextState) }

    render() 渲染

    • 作用:重新渲染組件,與Mounting階段的render是同一個(gè)函數(shù)
    • 注意:這個(gè)函數(shù)能夠執(zhí)行多次,只要組件的屬性或狀態(tài)改變了,這個(gè)方法就會(huì)重新執(zhí)行

    componentDidUpdate()

    • 作用:組件已經(jīng)被更新
    • 參數(shù):舊的屬性和狀態(tài)對(duì)象
    componentDidUpdate(prevProps, prevState) {console.warn('componentDidUpdate', prevProps, prevState) }

    組件生命周期 - 卸載階段(Unmounting)

    • 組件銷毀階段:組件卸載期間,函數(shù)比較單一,只有一個(gè)函數(shù),這個(gè)函數(shù)也有一個(gè)顯著的特點(diǎn):組件一輩子只能執(zhí)行依次!
    • 使用說(shuō)明:只要組件不再被渲染到頁(yè)面中,那么這個(gè)方法就會(huì)被調(diào)用( 渲染到頁(yè)面中 -> 不再渲染到頁(yè)面中 )

    componentWillUnmount()

    • 作用:在卸載組件的時(shí)候,執(zhí)行清理工作,比如
      • 清除定時(shí)器
      • 清除componentDidMount創(chuàng)建的DOM對(duì)象

    React - createClass(不推薦)

    • React.createClass({}) 方式,創(chuàng)建有狀態(tài)組件,該方式已經(jīng)被廢棄!!!
    • 通過(guò)導(dǎo)入 require('create-react-class'),可以在不適用ES6的情況下,創(chuàng)建有狀態(tài)組件
    • getDefaultProps() 和 getInitialState() 方法:是 createReactClass() 方式創(chuàng)建組件中的兩個(gè)函數(shù)
    • React without ES6
    • React 不適用ES6
    var createReactClass = require('create-react-class'); var Greeting = createReactClass({// 初始化 propsgetDefaultProps: function() {console.log('getDefaultProps');return {title: 'Basic counter!!!'}},// 初始化 stategetInitialState: function() {console.log('getInitialState');return {count: 0}},render: function() {console.log('render');return (<div><h1>{this.props.title}</h1><div>{this.state.count}</div><input type='button' value='+' onClick={this.handleIncrement} /></div>);},handleIncrement: function() {var newCount = this.state.count + 1;this.setState({count: newCount});},propTypes: {title: React.PropTypes.string} });ReactDOM.render(React.createElement(Greeting),document.getElementById('app') );

    state和setState

    • 注意:使用 setState() 方法修改狀態(tài),狀態(tài)改變后,React會(huì)重新渲染組件
    • 注意:不要直接修改state屬性的值,這樣不會(huì)重新渲染組件!!!
    • 使用:1 初始化state 2 setState修改state
    // 修改state(不推薦使用) // https://facebook.github.io/react/docs/state-and-lifecycle.html#do-not-modify-state-directly this.state.test = '這樣方式,不會(huì)重新渲染組件'; constructor(props) {super(props)// 正確姿勢(shì)!!!// -------------- 初始化 state --------------this.state = {count: props.initCount} }componentWillMount() {// -------------- 修改 state 的值 --------------// 方式一:this.setState({count: this.state.count + 1})this.setState({count: this.state.count + 1}, function(){// 由于 setState() 是異步操作,所以,如果想立即獲取修改后的state// 需要在回調(diào)函數(shù)中獲取// https://doc.react-china.org/docs/react-component.html#setstate});// 方式二:this.setState(function(prevState, props) {return {counter: prevState.counter + props.increment}})// 或者 - 注意: => 后面需要帶有小括號(hào),因?yàn)榉祷氐氖且粋€(gè)對(duì)象this.setState((prevState, props) => ({counter: prevState.counter + props.increment})) }

    推薦大家使用Fundebug,一款很好用的BUG監(jiān)控工具~

    組件綁定事件

    • 通過(guò)React事件機(jī)制 onClick 綁定
    • JS原生方式綁定(通過(guò) ref 獲取元素)
      • 注意:ref 是React提供的一個(gè)特殊屬性
      • ref的使用說(shuō)明:react ref

    React中的事件機(jī)制(推薦)

    • 注意:事件名稱采用駝峰命名法
    • 例如:onClick 用來(lái)綁定單擊事件
    <input type="button" value="觸發(fā)單擊事件"onClick={this.handleCountAdd}onMouseEnter={this.handleMouseEnter} />

    JS原生方式(知道即可)

    • 說(shuō)明:給元素添加 ref 屬性,然后,獲取元素綁定事件
    // JSX // 將當(dāng)前DOM的引用賦值給 this.txtInput 屬性 <input ref={ input => this.txtInput = input } type="button" value="我是豆豆" />componentDidMount() {// 通過(guò) this.txtInput 屬性獲取元素綁定事件this.txtInput.addEventListener(() => {this.setState({count:this.state.count + 1})}) }

    事件綁定中的this

    • 通過(guò) bind 綁定
    • 通過(guò) 箭頭函數(shù) 綁定

    通過(guò)bind綁定

    • 原理:bind能夠調(diào)用函數(shù),改變函數(shù)內(nèi)部this的指向,并返回一個(gè)新函數(shù)
    • 說(shuō)明:bind第一個(gè)參數(shù)為返回函數(shù)中this的指向,后面的參數(shù)為傳給返回函數(shù)的參數(shù)
    // 自定義方法: handleBtnClick(arg1, arg2) {this.setState({msg: '點(diǎn)擊事件修改state的值' + arg1 + arg2}) }render() {return (<div><button onClick={// 無(wú)參數(shù)// this.handleBtnClick.bind(this)// 有參數(shù)this.handleBtnClick.bind(this, 'abc', [1, 2])}>事件中this的處理</button><h1>{this.state.msg}</h1></div>) }
    • 在構(gòu)造函數(shù)中使用bind
    constructor() {super()this.handleBtnClick = this.handleBtnClick.bind(this) }// render() 方法中: <button onClick={ this.handleBtnClick }>事件中this的處理</button>

    通過(guò)箭頭函數(shù)綁定

    • 原理:箭頭函數(shù)中的this由所處的環(huán)境決定,自身不綁定this
    <input type="button" value="在構(gòu)造函數(shù)中綁定this并傳參" onClick={() => { this.handleBtnClick('參數(shù)1', '參數(shù)2') } } />handleBtnClick(arg1, arg2) {this.setState({msg: '在構(gòu)造函數(shù)中綁定this并傳參' + arg1 + arg2}); }

    受控組件

    • 表單和受控組件
    • 非受控組件

    在HTML當(dāng)中,像input,textarea和select這類表單元素會(huì)維持自身狀態(tài),并根據(jù)用戶輸入進(jìn)行更新。 在React中,可變的狀態(tài)通常保存在組件的state中,并且只能用 setState() 方法進(jìn)行更新. React根據(jù)初始狀態(tài)渲染表單組件,接受用戶后續(xù)輸入,改變表單組件內(nèi)部的狀態(tài)。 因此,將那些值由React控制的表單元素稱為:受控組件。

    • 受控組件的特點(diǎn):
      • 1 表單元素
      • 2 由React通過(guò)JSX渲染出來(lái)
      • 3 由React控制值的改變,也就是說(shuō)想要改變?cè)氐闹?#xff0c;只能通過(guò)React提供的方法來(lái)修改
    • 注意:只能通過(guò)setState來(lái)設(shè)置受控組件的值
    // 模擬實(shí)現(xiàn)文本框數(shù)據(jù)的雙向綁定 <input type="text" value={this.state.msg} onChange={this.handleTextChange}/>// 當(dāng)文本框內(nèi)容改變的時(shí)候,觸發(fā)這個(gè)事件,重新給state賦值 handleTextChange = event => {console.log(event.target.value)this.setState({msg: event.target.value}) }

    props校驗(yàn)

    • 作用:通過(guò)類型檢查,提高程序的穩(wěn)定性
    • 命令:npm i -S prop-types
    • 類型校驗(yàn)文檔
    • 使用:給類提供一個(gè)靜態(tài)屬性 propTypes(對(duì)象),來(lái)約束props
    // 引入模塊 import PropTypes from 'prop-types'// ...以下代碼是類的靜態(tài)屬性: // propTypes 靜態(tài)屬性的名稱是固定的!!! static propTypes = {initCount: PropTypes.number, // 規(guī)定屬性的類型initAge: PropTypes.number.isRequired // 規(guī)定屬性的類型,且規(guī)定為必傳字段 }

    React 單向數(shù)據(jù)流

    • React 中采用單項(xiàng)數(shù)據(jù)流
    • 數(shù)據(jù)流動(dòng)方向:自上而下,也就是只能由父組件傳遞到子組件
    • 數(shù)據(jù)都是由父組件提供的,子組件想要使用數(shù)據(jù),都是從父組件中獲取的
    • 如果多個(gè)組件都要使用某個(gè)數(shù)據(jù),最好將這部分共享的狀態(tài)提升至他們最近的父組件當(dāng)中進(jìn)行管理
    • 單向數(shù)據(jù)流
    • 狀態(tài)提升

    react中的單向數(shù)據(jù)流動(dòng):

    • 數(shù)據(jù)應(yīng)該是從上往下流動(dòng)的,也就是由父組件將數(shù)據(jù)傳遞給子組件
    • 數(shù)據(jù)應(yīng)該是由父組件提供,子組件要使用數(shù)據(jù)的時(shí)候,直接從子組件中獲取

    在我們的評(píng)論列表案例中:

    • 數(shù)據(jù)是由CommentList組件(父組件)提供的
    • 子組件 CommentItem 負(fù)責(zé)渲染評(píng)論列表,數(shù)據(jù)是由 父組件提供的
    • 子組件 CommentForm 負(fù)責(zé)獲取用戶輸入的評(píng)論內(nèi)容,最終也是把用戶名和評(píng)論內(nèi)容傳遞給了父組件,由父組件負(fù)責(zé)處理這些數(shù)據(jù)( 把數(shù)據(jù)交給 CommentItem 由這個(gè)組件負(fù)責(zé)渲染 )

    組件通訊

    • 父 -> 子:props
    • 子 -> 父:父組件通過(guò)props傳遞回調(diào)函數(shù)給子組件,子組件調(diào)用函數(shù)將數(shù)據(jù)作為參數(shù)傳遞給父組件
    • 兄弟組件:因?yàn)镽eact是單向數(shù)據(jù)流,因此需要借助父組件進(jìn)行傳遞,通過(guò)父組件回調(diào)函數(shù)改變兄弟組件的props
    • React中的狀態(tài)管理: flux(提出狀態(tài)管理的思想) -> Redux -> mobx
    • Vue中的狀態(tài)管理: Vuex
    • 簡(jiǎn)單來(lái)說(shuō),就是統(tǒng)一管理了項(xiàng)目中所有的數(shù)據(jù),讓數(shù)據(jù)變的可控
    • 組件通訊

    Context特性

    • 注意:如果不熟悉React中的數(shù)據(jù)流,不推薦使用這個(gè)屬性
      • 這是一個(gè)實(shí)驗(yàn)性的API,在未來(lái)的React版本中可能會(huì)被更改
    • 作用:跨級(jí)傳遞數(shù)據(jù)(爺爺給孫子傳遞數(shù)據(jù)),避免向下每層手動(dòng)地傳遞props
    • 說(shuō)明:需要配合PropTypes類型限制來(lái)使用
    class Grandfather extends React.Component {// 類型限制(必須),靜態(tài)屬性名稱固定static childContextTypes = {color: PropTypes.string.isRequired}// 傳遞給孫子組件的數(shù)據(jù)getChildContext() {return {color: 'red'}}render() {return (<Father></Father>)} }class Child extends React.Component {// 類型限制,靜態(tài)屬性名字固定static contextTypes = {color: PropTypes.string}render() {return (// 從上下文對(duì)象中獲取爺爺組件傳遞過(guò)來(lái)的數(shù)據(jù)<h1 style={{ color: this.context.color }}>爺爺告訴文字是紅色的</h1>)} }class Father extends React.Component {render() {return (<Child></Child>)} }

    react-router

    • react router 官網(wǎng)
    • react router github
    • 安裝:npm i -S react-router-dom

    基本概念說(shuō)明

    • Router組件本身只是一個(gè)容器,真正的路由要通過(guò)Route組件定義

    使用步驟

    • 1 導(dǎo)入路由組件
    • 2 使用 <Router></Router> 作為根容器,包裹整個(gè)應(yīng)用(JSX)
      • 在整個(gè)應(yīng)用程序中,只需要使用一次
    • 3 使用 <Link to="/movie"></Link> 作為鏈接地址,并指定to屬性
    • 4 使用 <Route path="/" compoent={Movie}></Route> 展示路由內(nèi)容
    // 1 導(dǎo)入組件 import {HashRouter as Router,Link, Route } from 'react-router-dom'// 2 使用 <Router> <Router>// 3 設(shè)置 Link<Menu.Item key="1"><Link to="/">首頁(yè)</Link></Menu.Item><Menu.Item key="2"><Link to="/movie">電影</Link></Menu.Item><Menu.Item key="3"><Link to="/about">關(guān)于</Link></Menu.Item>// 4 設(shè)置 Route// exact 表示:絕對(duì)匹配(完全匹配,只匹配:/)<Route exact path="/" component={HomeContainer}></Route><Route path="/movie" component={MovieContainer}></Route><Route path="/about" component={AboutContainer}></Route></Router>

    注意點(diǎn)

    • <Router></Router>:作為整個(gè)組件的根元素,是路由容器,只能有一個(gè)唯一的子元素
    • <Link></Link>:類似于vue中的<router-link></router-link>標(biāo)簽,to 屬性指定路由地址
    • <Route></Route>:類似于vue中的<router-view></router-view>,指定路由內(nèi)容(組件)展示位置

    路由參數(shù)

    • 配置:通過(guò)Route中的path屬性來(lái)配置路由參數(shù)
    • 獲取:this.props.match.params 獲取
    // 配置路由參數(shù) <Route path="/movie/:movieType"></Route>// 獲取路由參數(shù) const type = this.props.match.params.movieType

    路由跳轉(zhuǎn)

    • react router - history
    • history.push() 方法用于在JS中實(shí)現(xiàn)頁(yè)面跳轉(zhuǎn)
    • history.go(-1) 用來(lái)實(shí)現(xiàn)頁(yè)面的前進(jìn)(1)和后退(-1)
    this.props.history.push('/movie/movieDetail/' + movieId)

    fetch

    • 作用:Fetch 是一個(gè)現(xiàn)代的概念, 等同于 XMLHttpRequest。它提供了許多與XMLHttpRequest相同的功能,但被設(shè)計(jì)成更具可擴(kuò)展性和高效性。
    • fetch() 方法返回一個(gè)Promise對(duì)象

    fetch 基本使用

    • fetch Response
    • fetch 介紹
    • Javascript 中的神器——Promise
    /*通過(guò)fetch請(qǐng)求回來(lái)的數(shù)據(jù),是一個(gè)Promise對(duì)象.調(diào)用then()方法,通過(guò)參數(shù)response,獲取到響應(yīng)對(duì)象調(diào)用 response.json() 方法,解析服務(wù)器響應(yīng)數(shù)據(jù)再次調(diào)用then()方法,通過(guò)參數(shù)data,就獲取到數(shù)據(jù)了 */ fetch('/api/movie/' + this.state.movieType)// response.json() 讀取response對(duì)象,并返回一個(gè)被解析為JSON格式的promise對(duì)象.then((response) => response.json())// 通過(guò) data 獲取到數(shù)據(jù).then((data) => {console.log(data);this.setState({movieList: data.subjects,loaing: false})})

    推薦大家使用Fundebug,一款很好用的BUG監(jiān)控工具~

    跨域獲取數(shù)據(jù)的三種常用方式

    • JSONP
    • 代理
    • CORS

    JSONP

    • 安裝:npm i -S fetch-jsonp
    • 利用JSONP實(shí)現(xiàn)跨域獲取數(shù)據(jù),只能獲取GET請(qǐng)求
    • fetch-jsonp
    • fetch-jsonp
    • 限制:1 只能發(fā)送GET請(qǐng)求 2 需要服務(wù)端支持JSONP請(qǐng)求
    /* movielist.js */ fetchJsonp('https://api.douban.com/v2/movie/in_theaters').then(rep => rep.json()).then(data => { console.log(data) })

    代理

    • webpack-dev-server 代理配置如下:
    • 問(wèn)題:webpack-dev-server 是開發(fā)期間使用的工具,項(xiàng)目上線了就不再使用 webpack-dev-server
    • 解決:項(xiàng)目上線后的代碼,也是會(huì)部署到一個(gè)服務(wù)器中,這個(gè)服務(wù)器配置了代理功能即可(要求兩個(gè)服務(wù)器中配置的代理規(guī)則相同)
    // webpack-dev-server的配置 devServer: {// https://webpack.js.org/configuration/dev-server/#devserver-proxy// https://github.com/chimurai/http-proxy-middleware#http-proxy-options// http://www.jianshu.com/p/3bdff821f859proxy: {// 使用:/api/movie/in_theaters// 訪問(wèn) ‘/api/movie/in_theaters’ ==> 'https://api.douban.com/v2/movie/in_theaters''/api': {// 代理的目標(biāo)服務(wù)器地址target: 'https://api.douban.com/v2',// https請(qǐng)求需要該設(shè)置secure: false,// 必須設(shè)置該項(xiàng)changeOrigin: true,// '/api/movie/in_theaters' 路徑重寫為:'/movie/in_theaters'pathRewrite: {"^/api" : ""}}} }/* movielist.js */ fetch('/api/movie/in_theaters').then(function(data) {// 將服務(wù)器返回的數(shù)據(jù)轉(zhuǎn)化為 json 格式return data.json()}).then(function(rep) {// 獲取上面格式化后的數(shù)據(jù)console.log(rep);})

    CORS - 服務(wù)器端配合

    • 示例:NodeJS設(shè)置跨域
    • 跨域資源共享 CORS 詳解 - 阮一峰
    // 通過(guò)Express的中間件來(lái)處理所有請(qǐng)求 app.use('*', function (req, res, next) {// 設(shè)置請(qǐng)求頭為允許跨域res.header('Access-Control-Allow-Origin', '*');// 設(shè)置服務(wù)器支持的所有頭信息字段res.header('Access-Control-Allow-Headers', 'Content-Type,Content-Length, Authorization,Accept,X-Requested-With');// 設(shè)置服務(wù)器支持的所有跨域請(qǐng)求的方法res.header('Access-Control-Allow-Methods', 'POST,GET');// next()方法表示進(jìn)入下一個(gè)路由next(); });

    redux

    • 狀態(tài)管理工具,用來(lái)管理應(yīng)用中的數(shù)據(jù)
    • Action:行為的抽象,視圖中的每個(gè)用戶交互都是一個(gè)action
      • 比如:點(diǎn)擊按鈕
    • Reducer:行為響應(yīng)的抽象,也就是:根據(jù)action行為,執(zhí)行相應(yīng)的邏輯操作,更新state
      • 比如:點(diǎn)擊按鈕后,添加任務(wù),那么,添加任務(wù)這個(gè)邏輯放到 Reducer 中
      • 創(chuàng)建State
    • Store:
      • Redux應(yīng)用只能有一個(gè)store
      • getState():獲取state
      • dispatch(action):更新state
    /* action */// 在 redux 中,action 就是一個(gè)對(duì)象 // action 必須提供一個(gè):type屬性,表示當(dāng)前動(dòng)作的標(biāo)識(shí) // 其他的參數(shù):表示這個(gè)動(dòng)作需要用到的一些數(shù)據(jù) { type: 'ADD_TODO', name: '要添加的任務(wù)名稱' }// 這個(gè)動(dòng)作表示要切換任務(wù)狀態(tài) { type: 'TOGGLE_TODO', id: 1 } /* reducer */// 第一個(gè)參數(shù):表示狀態(tài)(數(shù)據(jù)),我們需要給初始狀態(tài)設(shè)置默認(rèn)值 // 第二個(gè)參數(shù):表示 action 行為 function todo(state = [], action) {switch(action.type) {case 'ADD_TODO':state.push({ id: Math.random(), name: action.name, completed: false })return statecase 'TOGGLE_TODO':for(var i = 0; i < state.length; i++) {if (state[i].id === action.id) {state[i].completed = !state[i].completedbreak}}return statedefault:return state} }// 要執(zhí)行 ADD_TODO 這個(gè)動(dòng)作: dispatch( { type: 'ADD_TODO', name: '要添加的任務(wù)名稱' } )// 內(nèi)部會(huì)調(diào)用 reducer todo(undefined, { type: 'ADD_TODO', name: '要添加的任務(wù)名稱' })

    推薦大家使用Fundebug,一款很好用的BUG監(jiān)控工具~

    相關(guān)文章

    • React數(shù)據(jù)流和組件間的溝通總結(jié)
    • 單向數(shù)據(jù)流和雙向綁定各有什么優(yōu)缺點(diǎn)?
    • 怎么更好的理解虛擬DOM?
    • React中文文檔
    • React 源碼剖析系列 - 不可思議的 react diff
    • 深入淺出React(四):虛擬DOM Diff算法解析

    轉(zhuǎn)載于:https://my.oschina.net/u/3375885/blog/3060016

    總結(jié)

    以上是生活随笔為你收集整理的React入门看这篇就够了的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。