React 基礎學習筆記

React 基礎學習筆記

黑馬程序員視頻:傳送門

1. React 基礎

1.1 介紹react

React起源于Facebook的內部項目卜朗,Instagram交友網站感憾;React設計思維及其獨特凯傲,屬于革命性創(chuàng)新教届,代碼邏輯卻非常簡單栗涂;

首先清楚兩個概念:

  • library(庫):小而巧的是庫苇侵,只提供了特定的API,如 jQuery历恐;庫的優(yōu)點是小巧方便寸癌,很方便的進行庫之間的切換,代碼沒有多大的改變弱贼;

  • Framework(框架):大而全的是框架蒸苇;框架提供的是一整套解決的方案;若在項目中切換不同框架吮旅,是比較困難的溪烤;

1.2.三大框架的現狀

三大框架互相抄;

  • Angular.Js:較早的前端框架庇勃,學習曲線較陡檬嘀,NG1學起來比較麻煩,NG2-NG5進行了一系列改革匪凉,引入了組件化的思維务唐,且支持TS編程父腕;

  • Vue.js:最火(關注最多)的前端框架役耕,中文文檔友好秽五;

  • React.js:最流行(使用最多)的前端框架,設計很優(yōu)秀聂受;

1.3.從組件化方面對比React和Vue

1.3.1 組件化方面

  • 什么是模塊化蒿秦?

    • 模塊化是從代碼的角度進行分析;

    • 開發(fā)中把一些可復用的代碼抽離為整個的模塊蛋济,便于項目的維護開發(fā)棍鳖;

  • 什么是組件化?

    • 組件化是從UI界面的角度進行分析碗旅;

    • 把一些可復用的UI元素(如輪播圖)抽離為單獨的組件渡处;

  • 組件化的好處?

    • 隨著項目規(guī)模的增大祟辟,組件就越來越多医瘫,組件化便于開發(fā)與維護;
  • Vue是如何實現組件化的旧困?

    • .vue文件來創(chuàng)建對應的組件醇份,文件包含template結構 script行為 style樣式結構稼锅;

    • 使用Vue.component() 或 Vue.extends()創(chuàng)建組件;

  • React是如何實現組件化的僚纷?

    • React 中有組件化的概念矩距,但是和Vue中的組件模板文件不同,在React中一切都是以Js運行的怖竭,因此學習React锥债,JS必須要合格,熟悉使用ES6和ES7(async和await)侵状;

1.4.從其它角度對比React和Vue

1.4.1 開發(fā)團隊方面

  • React:由Facebook前端開發(fā)團隊維護和更新赞弥;,技術實力比較雄厚趣兄;

  • Vue:由尤雨溪的開發(fā)團隊進行開發(fā)和維護;

1.4.2 社區(qū)方面

  • React:誕生時間早悼嫉,社區(qū)很強大艇潭,一些常見的問題、坑戏蔑、最優(yōu)解決方案蹋凝、文檔、博客在社區(qū)中都可以方便找到总棵;

  • Vue:相對React小些鳍寂,可能有一些坑沒有踩過;

1.4.3 移動App體驗方面

  • React:結合ReactNative情龄,提供了無縫遷移到移動APP的開發(fā)體驗(RN用的最多且最火迄汛,許多大公司都在使用來開發(fā)手機App);

  • Vue:結合Weex技術骤视,提供了遷移到移動端APP開發(fā)的體驗(阿里的項目使用)鞍爱;

1.5.為什么要學習React

  1. 對比Angular.js,React更加優(yōu)秀专酗,一切基于JS并實現了組件化開發(fā)的思想睹逃;

  2. 開發(fā)團隊實力強大,不用擔心斷更的情況祷肯;

  3. 社區(qū)強大沉填,許多問題都有最優(yōu)解決方案;

  4. 提供了無縫轉接到ReactNative 上的開發(fā)體驗佑笋,擴展了我們的技術能力翼闹,增強核心競爭力;

  5. 很多大型企業(yè)都采用了React.js作為前端項目的技術選型允青;

1.6.介紹DOM和虛擬DOM的概念

1.6.1 虛擬DOM

  • DOM的本質是什么橄碾?

    • DOM(文檔對象模型)是瀏覽器中的概念卵沉,用JS對象來表示頁面上的元素,并提供了操作DOM對象的API ;
  • 什么是React中的虛擬DOM法牲?

    • 虛擬DOM是框架中的概念史汗,是程序猿用JS對象來模擬頁面中的DOM元素和DOM嵌套關系;
  • 為什么要實現虛擬DOM(目的)拒垃?

    • 為了實現頁面中的DOM元素高效的更新停撞;
  • DOM和虛擬DOM的區(qū)別:

    • DOM:瀏覽器中提供的概念,用JS對象表示頁面上的元素悼瓮,提供操作DOM元素的API戈毒;

    • 虛擬DOM:框架中的概念,由開發(fā)框架的程序員手動用JS對象模擬DOM元素及其嵌套關系横堡;本質就是使用JS對象模擬DOM元素和其嵌套關系埋市,其目的就是為了實現頁面元素的高效更新;

1.6.2 diff 算法(下方)

1.7.虛擬DOM的本質和目的

虛擬DOM的本質就是使用JS對象模擬DOM元素和其嵌套關系命贴,其目的就是為了實現頁面元素的高效更新道宅;

1.7.1 實際的列表排序案例進行分析

案例:實際需求,點擊列表的頭胸蛛,進行對應的表格數據的排序(table表格數據):

  1. 表格中的數據從哪兒來的:從數據庫中查詢回來的污茵;

  2. 這些查詢的數據存放位置:數據在瀏覽器的內存中存放,而且是以對象數組的形式表示的葬项;

  3. 這些數據是怎么渲染到頁面上的:

  • a. 手動for循環(huán)整個對象數組泞当,然后手動拼接字符串(+號拼接符);

  • b. 使用模板引擎民珍,如 art.template(與a方法實質一樣)襟士;

  1. 思考:上述的a、b方案有沒有性能上的問題穷缤?

  2. 如果用戶點擊了一列的表頭(如:時間排序從大到械蟹洹),做法是:

  • 第一步津肛,觸發(fā)點擊事件章喉,把內存中的數組重新排序;

  • 第二步身坐,排序完畢后秸脱,頁面還未更新,內存中對象數組是新的部蛇;

  • 第三步摊唇,想辦法把更新的數據重新渲染到頁面中(判斷有沒有性能上的問題);

  1. 分析總結:上述方案只實現了將數據渲染到頁面中涯鲁,但是并沒有把性能做到最優(yōu)巷查;

  2. 如何才能把性能做到最優(yōu)有序?

  • 按需渲染頁面(只重新渲染更新的數據對應的頁面元素)
  1. 如何實現按需渲染岛请?
  • 理解DOM樹概念以及瀏覽器渲染DOM的相關知識旭寿;

  • 獲取并對比內存中新的DOM樹和舊的DOM樹的區(qū)別,只更新改動的DOM元素崇败;

  1. 如何獲取到內存中的DOM樹盅称,從而實現DOM樹的對比?
  • 分析:在瀏覽器中并沒有直接獲取DOM樹的API后室,因而無法拿到從瀏覽器內存中的DOM樹缩膝;
  1. 我們程序員可以手動模擬新舊兩顆DOM樹;

  2. 程序員如何手動模擬DOM樹岸霹?如何模擬一個DOM元素疾层?

  • 使用JS模擬一個DOM元素;

<div id="myDiv" title= "標題" data-index= "0">

  內容信息

  <p>哈哈哈</p>

</div>

// 下面通過JS對象模擬了上面的DOM樹結構

var div = {

  tagName: 'div',

  attrs: {id: 'myDiv', title: '標題', 'data-index': '0'},

  childrens: [

    '內容信息',

    {

      tagName: 'p',

      attrs: {},

      childrens: [

        '哈哈哈',

      ]

    }

  ],

}

  1. 程序員手動模擬的這兩個新舊DOM樹贡避,就是React中的虛擬DOM的概念云芦;

1.7.2 虛擬DOM概念總結

虛擬DOM就是用JS對象形式來模擬頁面上的DOM嵌套關系;(虛擬DOM是以JS對象的形式存在的)

1.8.介紹Diff算法的概念

1.8.1 tree diff

把新舊兩顆DOM樹的每一層進行對比贸桶;當整顆DOM樹逐層對比完畢,則所需要被按需更新的元素必然能夠找到桌肴;

1.8.2 component diff

在每一層中進行的對比(tree diff)中皇筛,對比相應的組件級別的差別;若對比前后組件類型相同坠七,則暫時認為此組件不需要更新水醋;反之,會進行移除舊組件彪置,創(chuàng)建新組件拄踪,并追加到頁面上;

1.8.3 element diff

在進行組件對比的時候拳魁,若兩個組件的類型相同惶桐,則需要進行元素級別的對比;

1.9.webpack 4.x 最基本的使用步驟

1.9.1 使用webpack創(chuàng)建React的項目的步驟

  1. 進入項目文件夾潘懊,初始化項目姚糊,執(zhí)行 npm init -y指令,生成package.json文件授舟;

  2. 項目文件夾根目錄下救恨,創(chuàng)建src目錄(存放代碼),dist目錄(項目打包的目錄)释树;

  3. 進入src目錄肠槽,新建一個index.html文件擎淤、index.js入口文件;

  4. 項目根目錄下進行安裝webpack打包工具秸仙,執(zhí)行npm install webpack -Dnpm install webpack-cli -D (webpack 4.X以上需要裝腳手架);

  5. 項目根目錄下新建一個webpack.config.js文件嘴拢,進行配置webpack打包的信息,使用module.export= { mode: 'development' // 新增mode屬性(必填)筋栋,值為development或者production炊汤,production表示壓縮打包的main.js文件 },使用的是NodeJs語法弊攘,webpack基于Node構建抢腐,支持Node API 語法;注意:webpack 4.X中的一個特性襟交,就是約定大于配置的概念迈倍,默認的打包入口entry的路徑就是src/index.js,打包輸出的文件路徑是dist/main.js捣域;

1.10.關于Node和Chrome之間的關系

1.10.1 module.export= {}export default {}的區(qū)別

  • module.export= {}:是Node中的概念啼染,在webpack不能使用export default {}進行替換;

  • export default {}:是ES6中向外導出的模塊的API焕梅,與之對應的是 import ** from '標識符'迹鹅;

1.10.2 哪些是Node支持的特性?

只要是Chrome里面支持的特性贞言,Node中就支持斜棚;因為NodeJs是基于Chrome V8引擎的JavaScript運行環(huán)境;可以使用babel插件進行轉換后使用该窗;

1.11.webpack-dev-server的基本使用

1.11.1 安裝使用webpack-dev-server進行自動編譯打包

  1. 安裝webpack-dev-server插件弟蚀,執(zhí)行npm i webpack-dev-server -D指令;

  2. 打開根目錄下的package.json文件酗失,在scripts屬性中增加"dev": "webpack-dev-server"

  3. 執(zhí)行npm run dev指令义钉,進行打包編譯,并編譯不會退出规肴,只要代碼改變會自動進行編譯捶闸,此時項目文件運行在本地的環(huán)境中,在 http://localhost:8080/中查看奏纪,注意實時打包生成的main.js文件位于根目錄下鉴嗤,實際是存放在內存中,并沒有替換dist下的main.js序调,可以看作是存在main.js文件醉锅,所有在index.html文件中導入的js<script src= "../dist/main.js"></script>改為<script src= "/main.js"></script>

  4. 可以在package.json文件中增加打包的其他信息发绢,如:"dev": "webpack-dev-server --open --port 3000 --hot --progress --compress --host 127.0.0.1"

webpack-dev-server是將生成文件放在內存中硬耍,這樣速度很快垄琐,并且對磁盤影響小经柴;

1.12.配置 html-webpack-plugin 插件

1.12.1 html-webpack-plugin 插件作用

該插件能夠將項目代碼生成到內存中去狸窘,安裝使用步驟:

  1. 安裝插件,執(zhí)行npm i html-webpack-plugin -D指令坯认;

  2. 打開根目錄下webpack.config.js文件翻擒,增加下面代碼:


const path= require('path');

// 導入 `html-webpack-plugin` 插件

const HtmlWebPackPlugin= require('html-webpack-plugin');

// 創(chuàng)建一個插件的實例對象

const htmlPlugin= new HtmlWebPackPlugin({

  template: path.join(__dirname, './src/index.html'), // 源文件

  filename: 'index.html' // 生成的內存中首頁的名稱

})

// 向外暴露一個打包的配置對象

module.export= {

  mode: 'development', // 新增mode屬性(必填),值為development或者production牛哺,production表示壓縮打包的main.js文件

  plugins: [

    htmlPlugin

  ]

}

  1. 瀏覽器中會展示出打包的代碼的效果陋气,可以查看源碼進行分析代碼;

  2. 接下來還需要配置babel插件引润;

1.13.使用React渲染最基本的虛擬DOM到頁面上

1.13.1 React 的安裝和使用

  1. 安裝巩趁,執(zhí)行npm i react react-dom -S指令,其中react專門用于創(chuàng)建組件和虛擬DOM淳附,組件的生命周期也在這個包中议慰;react-dom專門進行DOM操作,其中最主要的應用場景就是ReactDOM.render();

  2. index.html中奴曙,創(chuàng)建容器:<div id= "app"></div>别凹;

  3. 在入口文件main.js中導入包:


import React from 'react'

import ReactDOM from 'react-dom'

  1. 創(chuàng)建虛擬DOM元素:

// 創(chuàng)建虛擬DOM元素 <h1 title= "標題" id= "test">內容信息</h1>

// 第一個參數是字符串類型的參數,表示要創(chuàng)建的標簽的名稱洽糟;

// 第二個參數是對象類型的參數番川,表示創(chuàng)建的元素的屬性節(jié)點;

// 第三個參數是子節(jié)點

const myh1= React.createElement(

  'h1',

  {title: "標題", id: "test"},

  '內容信息'

)

  1. 渲染虛擬DOM元素到頁面中:

// 第一個參數表示要渲染的虛擬DOM對象脊框;

// 第二個參數表示指定容器,注意此處放的是一個容器的DOM對象践啄,并不是直接放容器元素的id字符串

ReactDOM.render(myh1, document.getElementById("app"))

1.14.使用React.createElement實現虛擬DOM嵌套

1.14.1 測試使用React.createElement建立虛擬DOM代碼


// 創(chuàng)建虛擬DOM元素 <h1 title= "標題" id= "test">內容信息</h1>

// 第一個參數是字符串類型的參數浇雹,表示要創(chuàng)建的標簽的名稱;

// 第二個參數是對象類型的參數屿讽,表示創(chuàng)建的元素的屬性節(jié)點昭灵;

// 第三個參數是子節(jié)點

const myh1= React.createElement(

  'h1',

  {title: "標題", id: "test"},

  '內容信息'

);

const mydiv= React.createElement(

  'div',

  null,

  myh1

);

// 第一個參數表示要渲染的虛擬DOM對象;

// 第二個參數表示指定容器伐谈,注意此處放的是一個容器的DOM對象烂完,并不是直接放容器元素的id字符串

ReactDOM.render(mydiv, document.getElementById("app"))

1.14.2 使用babel插件,直接寫HTML代碼

渲染頁面中的DOM結構诵棵,最好的方式就是寫HTML代碼:

1.15.在React項目中啟用JSX語法

1.15.1 最基礎的JSX語法代碼


// 1.導入包

import React from 'react'

import ReactDOM from 'react-dom'

// 2.創(chuàng)建虛擬DOM元素(虛擬DOM就是使用JS對象形式表示DOM和DOM間的嵌套關系)

const mydiv= React.createElement('div', {id:'test', title:"標題信息"}, "我是div內容");

// 3.調用render函數進行渲染

ReactDOM.render(mydiv, document.getElementById('app'))

1.15.2 使用babel插件抠蚣,直接寫HTML代碼


// 1.導入包

import React from 'react'

import ReactDOM from 'react-dom'

// 2.創(chuàng)建虛擬DOM元素(虛擬DOM就是使用JS對象形式表示DOM和DOM間的嵌套關系)

// const mydiv= React.createElement('div', {id:'test', title:"標題信息"}, "我是div內容");

// HTML 是最優(yōu)秀的標記語言,直接使用下面格式編寫會報錯履澳,因而使用babel插件轉換下列的標簽嘶窄;

// 注意:這種在JS中混合寫入類似與 HTML 的語法怀跛,叫做JSX語法;符合XML規(guī)范的JS柄冲;

// JSX的本質還是在運行的時候吻谋,使用babel轉換成了 React.createElement() 形式來運行的

const mydiv2= <div id= "test" title= "標題信息" >我是div內容</div>

// 3.調用render函數進行渲染

ReactDOM.render(mydiv, document.getElementById('app'))

1.15.3 babel 插件的安裝使用

  1. 安裝 babel 插件:

# loader/plugin 插件

npm install babel-core babel-loader babel-plugin-transform-runtime -D

# 語法

npm install babel-react-env babel-preset-stage-0 -D

  1. 安裝能識別 jsx 語法的包:

npm install babel-preset-react -D

  1. webpack.config.js配置文件中配置第三方loader的使用,在module.export= {...}中加入下面代碼现横,是由于webpack只支持.js結尾的文件漓拾,例如.vue .png 等文件是無法處理,此處的js中包含的html代碼webpack也是無法處理戒祠,因而需要配置:

module: { // 所有的第三方模塊的配置規(guī)則

  rules: [ // 第三方匹配規(guī)則

    {test: /\.js|jsx$/, use: 'babel-loader', exclude: /node_modules/}, // 千萬別忘記排除 node_modules中的文件

  ]

}

  1. 添加.babelrc 配置文件骇两,寫入下面內容:

{

  "presets": ["env", "stage-0", "react"],

  "plugins": ["transform-runtime"],

}

1.16.在JSX中書寫JS代碼

1.16.1 在JSX中混合寫入js表達式

jsx語法中,要把JS代碼寫到{}中去得哆,在{}里面就是按照js的寫法就行脯颜;區(qū)別于在Vue中的插值表達式語法 {{}}雙大括號;

  • 渲染數字贩据;

  • 渲染字符串栋操;

  • 渲染Boolean值;

  • 為屬性綁定值饱亮;

  • 渲染jsx元素矾芙;

  • 渲染jsx元素數組(注意key的問題,key屬性會在增刪數組的時候影響數組中選中的元素)近上;

  • 將普通字符串數組剔宪,轉為jsx數組并渲染到頁面上(兩種方法);

注意:JSX語法中必須符合XML的語法規(guī)則壹无,對于Html標簽來說必須是閉合或者自閉合標簽葱绒,如 <hr/>

1.17.將普通字符串數組,轉為jsx數組并渲染到頁面上

1.17.1 方法一:手動在外部進行for循環(huán)


import React from 'react'

import ReactDOM from 'react-dom'

const arrStr= = ['111', '222', '333'];

// 定義一個空數組斗锭,用于存放標簽

const result= [];

arrStr.forEach(item=> {

  const temp= <h2>{item}</h2>;

  result.push(temp)

})

// 調用render函數進行渲染

ReactDOM.render(

  <div>

    {result}

  </div>

  , document.getElementById('app')

)

1.17.2 方法二:直接在內部進行for循環(huán)地淀,使用map函數


import React from 'react'

import ReactDOM from 'react-dom'

const arrStr= = ['111', '222', '333'];

// 調用render函數進行渲染

ReactDOM.render(

  <div>

    { arrStr.map(item => { return <h3>item</h3> }) }

  </div>

  , document.getElementById('app')

)

2. React 組件

2.1.演示Vue和React中key的作用

2.1.1 編程中對于JavaScript語句后面是否加分號的問題

必須加分號的情況:下一行的開頭是 [ ( + - / 五個符號之一,則該行末尾或下行開頭加分號岖是;

2.1.2 測試數組中key的作用

在React和Vue中的key的作用完全相同帮毁;

  1. 項目根目錄下新建一個test目錄,新建Vue的測試文件test.html vue.js豺撑;

  2. vue.js中寫單頁面的代碼茶行,實現渲染一個數組的功能案狠,對于數組的每個元素能夠進行選中,也能夠對數組的元素進行增刪操作,測試沒有綁定key時呻此,手動增(unshift()方法)添加數組元素時會對與選擇的元素進行影響蔓搞;

總結:React 中使用map函數或者Vue中使用 v-for 循環(huán),若想保持數組元素的狀態(tài)(如:是否選中,Vue中動畫)跃巡,就一定要對key屬性進行綁定;在React中牧愁,需要把key添加給被forEach或map或for循環(huán)直接控制的元素素邪;


import React from 'react'

import ReactDOM from 'react-dom'

const arrStr= = ['111', '222', '333'];

// 調用render函數進行渲染

ReactDOM.render(

  <div>

    { arrStr.map(item => { return <h3 key= { item.id }> item </h3> }) }

  </div>

  , document.getElementById('app')

)

2.2.關于jsx語法的注意事項

  1. 在JSX 中寫注釋:
  • 多行注釋(推薦使用): {/* 注釋的內容 */}

  • 單行注釋:


{

  // 注釋的內容

}

  1. 在JSX中的元素添加class類名:使用className替代class;其次猪半,使用htmlFor替換label標簽的for屬性兔朦,兩者原因是由于class for也是JavaScript中關鍵字,會出現沖突磨确;

  2. 在JSX創(chuàng)建DOM的時候沽甥,所有的節(jié)點必須由唯一的根元素進行包裹,如 <div>...</div>乏奥;

  3. 在JSX語法中摆舟,標簽必須成對出現,如果是單標簽邓了,一定要自閉合恨诱,如 <hr/>

2.3.創(chuàng)建組件的第一種方式并為組件傳遞props數據

2.3.1 使用構造函數來創(chuàng)建組件骗炉,并為組件傳遞數據


import React from 'react'

import ReactDOM from 'react-dom'

// 第一種創(chuàng)建組件的方式照宝,注意組件的首字母必須有大寫,調用的時候也是大寫

function Hello (props) { // props 用于接收參數句葵,該屬性是只讀的(在Vue中該屬性也是只讀的厕鹃,不能被重新賦值)

  // return null 表示此組件什么都不渲染

  // return null

  console.log('props:',props)

  // 在組件中必須返回一個合法的 JSX 虛擬DOM元素

  return <div>

    這是 Hello 組件

    -- {props.name}

    -- {props.age}

    -- {props.gender}

  </div>

}

const dog = {

  name: "大黃",

  age: 5,

  gender: "公"

}

// 調用render函數進行渲染

ReactDOM.render(

  <div>

    <Hello name= {dog.name} age= {dog.age} gender= {dog.gender} ></Hello>

  </div>

  , document.getElementById('app')

)

2.4.使用ES6的展開運算符簡化傳遞props數據的過程

一定要熟悉使用JavaScript的知識(ES5/6/7 語法知識);

2.4.1 使用ES6的展開運算符(...)傳遞對象乍丈、數組數據


// 調用render函數進行渲染

ReactDOM.render(

  <div>

    { /* <Hello name= {dog.name} age= {dog.age} gender= {dog.gender} ></Hello> */ }

    <Hello {...dog}></Hello>

  </div>

  , document.getElementById('app')

)

2.5.將組件抽離為單獨的.jsx文件

  1. 將組件的代碼抽離到單獨的文件中剂碴,使用export default xxx暴露出去組件;

  2. 使用import xxx from '...'需要導入組件轻专,不要省略后綴名汗茄;

  3. 注意還需要在抽離出去的單獨文件中增加:import React from 'react',是由于在抽離的文件中使用了JSX的語法铭若;

2.6.配置webpack從而在導入組件的時候,省略.jsx后綴名

webpack.config.js配置文件導出的對象中增加下面的代碼递览,注意是與module平級:


resolve: {

  extensions: ['.js', '.jsx', '.json'],  // 表示這幾個文件的后綴名可以省略不寫

}

2.7.配置webpack設置根目錄

2.7.1 設置src代碼目錄為@

webpack.config.js配置文件導出的對象中resolve下面增加代碼叼屠,注意是與上面的 extensions平級:


resolve: {

  extensions: ['.js', '.jsx', '.json'],  // 表示這幾個文件的后綴名可以省略不寫

  alias:{  // 表示別名

    '@': path.join(__dirname, './src'),  // 這樣 @ 符號就表示根目錄中src的這一層

  },

}

2.8.class-創(chuàng)建類并通過constructor掛載實例屬性

2.8.1 ES6 中class的使用


// 1.普通的構造函數創(chuàng)建對象

function Person (name, age) {

  this.name= name;  // 通過new出來的實例的this掛載的屬性稱為實例屬性;

  this.age= age;

}

const p1= new Person('大黑', '2')

console.log (p1)

// 2.使用class關鍵字創(chuàng)建類

class Animal {

  // 這是類中的構造器绞铃,每個類中都有一個構造器镜雨,若不寫,也會默認有一個空的constructor構造器

  // 構造器作用:使用new的時候默認執(zhí)行構造器constructor中的代碼

  constructor () (name, age) {

    this.name= name;  // 實例屬性

    this.age= age;

  }

}

const p2= new Person('小灰', '1')

console.log (p2)

2.9.class-使用static創(chuàng)建靜態(tài)屬性

2.9.1 靜態(tài)屬性定義

通過構造函數直接訪問到的屬性稱為靜態(tài)屬性儿捧,直接給了構造函數荚坞,不是通過this進行掛載的挑宠;

2.9.2 靜態(tài)屬性使用


// 1.普通的構造函數創(chuàng)建對象

function Person (name, age) {

  this.name= name;  // 通過new出來的實例的this掛載的屬性稱為實例屬性;

  this.age= age;

}

Person.info= 'aaa'  // info屬性直接掛載給構造函數颓影,稱為靜態(tài)屬性

// 將實例方法掛載到Person的原型對象上

Person.prototype.say = function () {

  console.log('這是Person的實例方法')

}

// 靜態(tài)方法各淀,實例的對象無法訪問該方法,只能通過 Person.show() 進行訪問诡挂,使用的少

Person.show= function () {

  console.log('這是Person的靜態(tài)方法')

}

// 實例化一個對象

const p1= new Person('大黑', '2')

console.log(p1.name)  // name 是 Person 的實例屬性

console.log(Person.info)  // info 是 Person 的靜態(tài)屬性

Person.say()  // say 是 Person 的實例方法

// 2.使用class關鍵字創(chuàng)建類

class Animal {

  constructor () (name, age) {

    this.name= name;  // 實例屬性

    this.age= age;

  }

  // 在class內部碎浇,通過static關鍵字修飾出來的屬性就是靜態(tài)屬性;

  static info= 'hahh';

  // 此處也是將實例方法掛載到Person的原型對象上

  eating () {

    console.log('這是Animal的實例方法')

  }

  // 靜態(tài)方法使用static關鍵字璃俗,使用的少

  static playing () {

    console.log('這是Animal的靜態(tài)方法')

  }

}

const p2= new Person('小灰', '1')

console.log (p2)

console.log(p2.name)  // name 是 Animal 的實例屬性

console.log(Animal.info)  // info 是 Animal 的靜態(tài)屬性

p2.eating()  // eating 是 Animal 的實例方法

2.10.class-實例方法和靜態(tài)方法(見上方)

2.11.class-總結class的基本用法和兩個注意點

  • 注意點1:在class內部只能寫 構造器奴璃、靜態(tài)屬性、靜態(tài)方法城豁、實例方法四種(實例屬性在構造器中)苟穆;

  • 注意點2:class關鍵字內部還是用原來的方法實現的,因此把class關鍵字稱為 語法糖唱星;

2.13.class-使用extends實現子類繼承父類

2.13.1 代碼案例


class American {

  constructor (name ,age) {

    this.name= name;

    this.age= age;

  }

}

const a1= new American('sara', '21')

class China {

  constructor (name ,age) {

    this.name= name;

    this.age= age;

  }

}

const c1= new China('wang', '21')

// 上面由于兩個類的屬性相同雳旅,可以通過創(chuàng)建一個父類

class Person {

  constructor (name ,age) {

    this.name= name;

    this.age= age;

  }

}

// 在class類中使用extends關鍵字,實現子類繼承父類魏颓,如下:

class American2 extends Person {

}

class China2 extends Person {

}

const a2= new American2('jack', '21')  // 會自動執(zhí)行父類中的構造函數

const c2= new China2('huang', '20')

2.14.class-子類訪問父類上的實例方法

2.14.1 代碼案例


// 創(chuàng)建一個父類

class Person {

  // 子類會繼承父類的構造函數

  constructor (name ,age) {

    this.name= name;

    this.age= age;

  }

  // 父類中的實例方法岭辣,作為公共的方法

  say () {

    console.log('say hello')

  }

}

// 在class類中使用extends關鍵字,實現子類繼承父類甸饱,如下:

class American2 extends Person {

}

class China2 extends Person {

}

const a2= new American2('jack', '21')  // 會自動執(zhí)行父類中的構造函數

a2.say()  // 調用父類中的實例方法

const c2= new China2('huang', '20')

2.15.class-constructor構造器中super函數的使用說明

2.15.1 問題討論及代碼案例

  • 為什么一定要在 constructor中調用super()?

    • 若一個子類通過 extends關鍵字繼承了父類沦童,那么子類構造器函數constructor()中,必須調用super()
  • super()有什么作用叹话?

    • super()是一個函數偷遗,是父類的構造器,子類中的super()就是父類中的構造器constructor()的引用驼壶;
  • super()中參數為空且沒有執(zhí)行的代碼時氏豌,實例的對象并不會繼承父類中的構造器函數中的實例屬性?

    • super()作為父類中的構造器constructor()的引用热凹,因此必須需要傳遞參數泵喘,因而才能正確的調用父類中的構造器函數;

// 創(chuàng)建一個父類

class Person {

  // 子類會繼承父類的構造函數

  constructor (name ,age) {

    this.name= name;

    this.age= age;

  }

  // 父類中的實例方法般妙,作為公共的方法

  say () {

    console.log('say hello')

  }

}

// 在class類中使用extends關鍵字纪铺,實現子類繼承父類,子類中實現構造器時碟渺,一定要加入`super()`方法并傳遞參數:

class China3 extends Person {

  constructor (name ,age) {

    super (name ,age)

  }

}

const c3= new China3('huang', '20')

2.16.class-為子類掛載獨有的實例屬性和實例方法

2.16.1 代碼案例


// 創(chuàng)建一個父類

class Person {

  // 子類會繼承父類的構造函數

  constructor (name ,age) {

    this.name= name;

    this.age= age;

  }

  // 父類中的實例方法鲜锚,作為公共的方法

  say () {

    console.log('say hello')

  }

}

// 在class類中使用extends關鍵字,實現子類繼承父類,子類中實現構造器時芜繁,一定要加入`super()`方法并傳遞參數旺隙,IdNumber參數是中國人獨有的,因而不能掛載到父類上:

class China3 extends Person {

  constructor (name ,age, IdNumber) {

    super (name ,age)

    // 單獨在子類中使用this進行綁定骏令;注意在子類中蔬捷,this只能放在super()后面;

    this.IdNumber= IdNumber;

  }

}

const c3= new China3('li', '20', '513*********')

2.17.使用class關鍵字創(chuàng)建組件

2.17.1 基本的class創(chuàng)建組件的語法


// 使用class創(chuàng)建組件伏社,必須要自己的組件繼承自 React.Component

class 組件名稱 extends React.Component {

  // 在組件內部抠刺,必須要這個 render() 函數,該函數的作用是渲染當前組件對應的虛擬DOM結構

  render () {

    // render() 函數必須返回合法的JSX虛擬DOM結構

    return <di>這是class創(chuàng)建的組件</div>

  }

}

創(chuàng)建了的實例在使用 ReactDOM.render() 的時候摘昌,作為標簽時相當于是使用new了一個實例對象

2.17.2 兩種創(chuàng)建類的方法的對比

  • 構造函數創(chuàng)建的函數速妖,叫做無狀態(tài)組件

  • class創(chuàng)建的函數聪黎,叫做有狀態(tài)組件罕容;

  • 什么狀況下使用有/無狀態(tài)的組件

    • 有/無狀態(tài)的組件的本質區(qū)別是:有無state屬性稿饰;

2.18.為class創(chuàng)建的組件傳遞props參數并直接使用this.props來訪問

2.18.1 代碼案例


import React from 'react'

import ReactDOM from 'react-dom'

class Movie extends React.Component {

  render () {

  // 在class關鍵字創(chuàng)建的組件中锦秒,若想使用外部傳遞的`props`參數,直接使用`this.props.xxx`訪問

    return <div>

      // 注意在組件class內部喉镰,this表示當前組件的實例對象旅择;同時props中的屬性都是只讀的,不能重新賦值

      這是Movie組件---{this.props.name}---{this.props.age}

    </div>

  }

}

const user= {

  name: 'wang',

  age: 22,

  gender: '男'

}

// 調用render函數進行渲染

ReactDOM.render(

  <div>

    { /* <Movie name= {user.name} age= {user.age}></Movie> */}

    <Movie {...age}></Movie>  { /* ES6簡寫的擴展對象的語法 */}

  </div>

  , document.getElementById('app')

)

2.19.介紹class創(chuàng)建的組件中this.state

2.19.1 兩種創(chuàng)建類的方法的對比

使用class關鍵字創(chuàng)建的組件具有自己的私有數據和生命周期函數侣姆,而使用function函數創(chuàng)建的組件只有props生真,沒有自己的私有數據和生命周期函數;

  1. 構造函數創(chuàng)建的函數捺宗,叫做無狀態(tài)組件柱蟀;

  2. class創(chuàng)建的函數,叫做有狀態(tài)組件蚜厉;

  3. 什么狀況下使用有/無狀態(tài)的組件长已?

  • 有/無狀態(tài)的組件的本質區(qū)別是:有無state屬性;

2.19.2 代碼案例


import React from 'react'

import ReactDOM from 'react-dom'

class Movie extends React.Component {

  // 在自定義構造器的時候必須要調用 super()

  constructor () {

    super ()

    // 只有在調用了super() 后才能使用this關鍵字

    this.state= {  // 這個this.state對象相當于Vue中的data(return {...})昼牛,其中的數據可讀可寫

      msg: '我是class創(chuàng)建得Movie組件'

    }

  }

  render () {

  // 在class關鍵字創(chuàng)建的組件中术瓮,若想使用外部傳遞的`props`參數,直接使用`this.props.xxx`訪問

    return <div>

      // 注意在組件class內部贰健,this表示當前組件的實例對象胞四;同時props中的屬性都是只讀的,不能重新賦值

      這是Movie組件---{this.props.name}---{this.props.age}

      <h2>{ this.state.msg }</h2>

    </div>

  }

}

const user= {

  name: 'wang',

  age: 22,

  gender: '男'

}

// 調用render函數進行渲染

ReactDOM.render(

  <div>

    { /* <Movie name= {user.name} age= {user.age}></Movie> */}

    <Movie {...age}></Movie>  { /* ES6簡寫的擴展對象的語法 */}

  </div>

  , document.getElementById('app')

)

2.20.介紹有狀態(tài)組件和無狀態(tài)組件的區(qū)別

  1. 構造函數創(chuàng)建的組件霎烙,叫做無狀態(tài)組件

  2. class創(chuàng)建的組件,叫做有狀態(tài)組件悬垃;

  • 若一個組件需要有私有數據游昼,推薦使用class創(chuàng)建的組件;
  1. 什么狀況下使用有/無狀態(tài)的組件尝蠕?
  • 有/無狀態(tài)的組件的本質區(qū)別是:有無state屬性烘豌;
  1. 組件中的 propsstate/data之間的區(qū)別:
  • props中的數據都是外界傳過來的數據;

  • state/data中的數據都是組件私有的(通過Ajax獲取回來的數據一般都是私有數據)看彼;

  • props中的數據都是只讀的廊佩,不可復寫;

  • state/data中的數據都是可讀可寫靖榕;

2.21.評論列表案例-創(chuàng)建CmtList組件并渲染基本頁面結構


// 1. 導入包

import React from 'react'

import ReactDOM from 'react-dom'

// 2. 使用class關鍵字創(chuàng)建組件

class Cmtlist extends React.Component {

  constructor () {

    super ()

    this.state= {

      msg: '組件的state中的信息',

      CommentList: [  // 評論列表數據

        {id: '1', user: 'aaa', content: '內容111'},

        {id: '2', user: 'bbb', content: '內容222'},

        {id: '3', user: 'ccc', content: '內容333'},

      ]

    }

  }

  render () {

    return <div>

      <h1>這是評論列表組件</h1>

      {this.state.CommentList.map( (item) => {

        <div key= {item.id}>

          <h3>評論人:{item.user}</h3>

          <p>評論內容:{item.content}</p>

        </div>

      })}

    </div>

  }

}

// 3. 使用ReactDOM.render渲染虛擬DOM到頁面中

ReactDOM.render(<div>

  <Cmtlist></Cmtlist>

</div>, document.getElementById('app'))

2.22.評論列表案例-將評論Item項抽離為單獨的CmtItem組件


// 1. 導入包

import React from 'react'

import ReactDOM from 'react-dom'

// 使用function定義每個評論項小組件

function CmtItem (props) {

  return <div>

    <h3>評論人:{props.user}</h3>

    <p>評論內容:{props.content}</p>

  </div>

}

//  使用class關鍵字創(chuàng)建評論框大組件

class Cmtlist extends React.Component {

  constructor () {

    super ()

    this.state= {

      msg: '組件的state中的信息',

      CommentList: [  // 評論列表數據

        {id: '1', user: 'aaa', content: '內容111'},

        {id: '2', user: 'bbb', content: '內容222'},

        {id: '3', user: 'ccc', content: '內容333'},

      ]

    }

  }

  render () {

    return <div>

      <h1>這是評論列表組件</h1>

      {this.state.CommentList.map( (item) => {

        <CmtItem {...item} key= {item.id}></CmtItem>

      })}

    </div>

  }

}

// 3. 使用ReactDOM.render渲染虛擬DOM到頁面中

ReactDOM.render(<div>

  <Cmtlist></Cmtlist>

</div>, document.getElementById('app'))

2.23.評論列表案例-將評論列表組件和評論項組件抽離為單獨的組件

關鍵點是使用export default進行組件暴露出去标锄,再使用import xxx from '...'進行組件的引入;

注意:在抽離出去的組件中茁计,按需添加導入import React from 'react'和其關聯(lián)的子組件料皇;

2.24.評論列表案例-演示@符號替代相對路徑的好處

由于在抽離子組件的過程中,對于有父子包含關系的組件的導入時星压,需要注意引入的路徑的問題践剂,因而考慮使用絕對路徑進行子組件的導入;在webpack.config.js配置文件導出的對象中resolve下面的alias屬性娜膘,使用@符號表示src代碼目錄逊脯,因而在項目中使用@符號進行路徑信息導入;

3. React 樣式

3.1.在組件中使用style行內樣式并封裝樣式對象

3.1.1 代碼案例(上一天的評論組件案例代碼)


render () {

  return <div>

    {/* 注意:在JSX中竣贪,若設置行內樣式時军洼,不能為 style 設置 字符串的值,而是該 tyle= { {color: 'red'} } 這么寫贾富,

    之前的css屬性中有連字符 - 時歉眷,需要用單引號包裹,或者寫成大寫字母颤枪;同時行內樣式中是數值類型的樣式汗捡,可以不用引號包裹,

    而字符串類型的樣式值必須用引號包裹畏纲,見下方的代碼 */}

    {/* <h1 style= "color: red">這是評論列表組件</h1> */}

    <h1 style= { { color: 'red', fontSize: '14px', zIndex: 10 } }>這是評論列表組件</h1>

  </div>

}

3.1.2 對樣式代碼進行封裝抽離

  • 從JSX代碼中抽離代碼成一個樣式對象扇住;

  • 對于多個抽離出來的各個樣式對象組成一個大的樣式對象;

  • 對于大的樣式對象單獨提到一個樣式對象的JS文件中盗胀,通過export default進行導出艘蹋,import xxx from 'xxx'進行導入;

3.2.使用css樣式表美化組件

3.2.1 使用 className 進行樣式的添加

項目使用 css 樣式文件步驟:

  1. 安裝style-loader css-loader 插件:npm i style-loader css-loader -D票灰;

  2. 配置webpack.config.js文件中的module=>rules增加下面的代碼:


rules: {

  {test: /\.js|jsx$/, use: 'babel-loader', exclude: /node_modules/}, // 千萬別忘記排除 node_modules中的文件

  { test: /\.css$/, use: ['style-loader', 'css-loader'] },  // 打包處理 css 樣式表的第三方loader女阀,順序是逆序宅荤,先是'css-loader'處理,再'style-loader'處理浸策;

}

  1. 在JSX代碼引入引入寫好的樣式文件冯键,使用className替代原來的class引入對于的class樣式;

render () {

  return <div>

    {/* 此處的 title 是在導入的css文件中編寫的 class 樣式庸汗,導入通過 : import xxx from 'xxx.css' */}

    <h1 className= "title">這是評論列表組件</h1>

  </div>

}

3.3.演示React中使用普通 css 樣式表的作用域沖突問題

3.3.1 思考問題

  1. 問題1:引入的樣式文件只在該文件中生效嗎惫确?
  • 經過測試發(fā)現,直接導入的css樣式表默認是會在整個項目(全局)都生效蚯舱,原因是由于樣式表沒有作用域改化;
  1. 問題2:Vue組件中中的樣式表是否也有樣式表沖突的問題,怎么解決呢枉昏?
  • Vue中通過 <style scoped></style>進行局部樣式設置陈肛;
  1. 問題3:React 中是否有和Vue 中一樣的 scoped 指令呢?
  • React 中沒有指令的概念凶掰;

3.4.為普通樣式表通過 modules 參數啟用模塊化

3.4.1 啟用Css樣式表的模塊化功能

  • 配置webpack.config.js文件中的module=>rules的css文件的第三分loader增加參數燥爷,方式是通過問號增加參數,其中有個固定的參數 modules 表示為普通的css樣式表啟用模塊化懦窘,代碼如下:

rules: {

  {test: /\.js|jsx$/, use: 'babel-loader', exclude: /node_modules/}, // 千萬別忘記排除 node_modules中的文件

  { test: /\.css$/, use: ['style-loader', 'css-loader?modules'] },  modules 參數只有 css-loader 才能使用

}

  • 修改在通過className引入的樣式表的值需要進行修改前翎,使用的為引入的那個樣式對象的名加屬性名:className= {xxx.title}

注意:css模塊化只是針對類選擇器(className= {...})和ID(id={...})選擇器生效,對于普通的css標簽選擇器不會進行模塊化

3.5.使用localIdentName來自定義模塊化的類名

3.5.1 自定義模塊化樣式表的名字畅涂,可選的參數有:

  • [path] :表示樣式表相對于項目根目錄的路徑港华;

  • [name]:表示樣式表文件名稱;

  • [local]:表示樣式的類名定義名稱午衰;

  • [hash:length]:表示32位的hash值立宜,可選值小于32就行;

3.5.2 代碼案例


rules: {

  {test: /\.js|jsx$/, use: 'babel-loader', exclude: /node_modules/}, // 千萬別忘記排除 node_modules中的文件

  { test: /\.css$/, use: [ 'style-loader', 'css-loader?modules&localIdentName=[path][name]-[local]-[hash:5]' ] },

}

3.6.通過local和global設置類名是否被模塊化

3.6.1 global 設置全局的class類

在css樣式表的文件中加入 :global()臊岸,讓被包裹的類名不被模塊化橙数,而是作為全局使用,寫法如下:


:global(.red) {

  color: red;

}

在同一個元素上增加兩個或多個類名方式可以是如下兩種:


<h1 className= { title + ' ' + 'red' }>這是評論列表組件</h1>

<h1 className= { [title, 'red'].join(' ') }>這是評論列表組件</h1>

3.6.2 local 設置局部的class類

在css樣式表的文件中加入 :local()帅戒,讓被包裹的類名被模塊化灯帮,而是作為局部使用,與不寫的效果一直逻住,是默認的行為钟哥;

3.7.在項目中為scss或less文件啟用模塊化

3.7.1 導入第三方樣式,如 Bootstrap

  1. 安裝 Bootstrap 第三方插件瞎访,執(zhí)行 npm i bootstrape@3.3.7 -S 指令腻贰;

  2. 在項目的代碼中進行 Bootstrap 樣式代碼進行導入,如下:


// 引入的包為 node_modules 目錄中時扒秸,可以省略node_modules 目錄播演,直接以包名開始引入自己的模塊

import bootCss from 'bootstrap/dist/css/bootsrtap.css'  // 引入Bootstrap包的代碼

  1. 根據當前的報錯提示信息發(fā)現冀瓦,webpack無法處理一些圖片文件,先下載第三方loader写烤,執(zhí)行npm i url-loader file-loader -D指令咕幻;再配置 webpack.config.js文件中的module=>rules的參數增加代碼,重新啟動項目后生效:

rules: {

  {test: /\.js|jsx$/, use: 'babel-loader', exclude: /node_modules/}, // 千萬別忘記排除 node_modules中的文件

  { test: /\.css$/, use: [ 'style-loader', 'css-loader?modules&localIdentName=[path][name]-[local]-[hash:5]' ] },

  {test: /\.ttf|woff|woff2|eot|svg$/, use: [ 'url-loader' ]}, // 打包處理字體文件的loader

}

  1. 注意在使用的時候顶霞,對于樣式文件做了模塊化處理,使用的方式變?yōu)樯厦媸褂脤ο蟮男问绞褂?使用有點兒麻煩):

使用bootstrap中的按鈕的樣式 btn btn-pramery 锣吼,如下:

<button className= { [bootCss.btn, bootCss['btn-primary']].join(' ') }></button>

  1. 希望使用第三方的樣式文件Bootstrap的方式选浑,如下面這種樣式:

使用bootstrap中的按鈕的樣式 btn btn-pramery ,如下:

<button className= "btn btn-primary"></button>

  1. 發(fā)現第三方的樣式表都是以.css結尾玄叠,那么我們自己定義的樣式文件可以使用sass less stylus來寫樣式文件古徒,因而配置樣式表的模塊化中,換為.scss .less .stylus結尾的樣式文件進行模塊化處理读恃,先需要安裝這些樣式文件的第三方loader插件隧膘,scss 安裝執(zhí)行npm i saaa-loader node-sass -D;再配置 webpack.config.js文件中的module=>rules的參數寺惫,導入樣式改為import 'bootstrap/dist/css/bootsrtap.css'測試驗證能夠正確使用:

rules: {

  { test: /\.js|jsx$/, use: 'babel-loader', exclude: /node_modules/ }, // 千萬別忘記排除 node_modules中的文件

  { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] },

  { test: /\.ttf|woff|woff2|eot|svg$/, use: [ 'url-loader' ] }, // 打包處理字體文件的loader

  { test: /\.scss$/, use: [ 'style-loader', 'css-loader?modules&localIdentName=[path][name]-[local]-[hash:5]', 'sass-loader'] } // 打包處理scss文件的loader

}

3.8.在React中為按鈕綁定點擊事件

3.8.1 React 的事件綁定機制

  • 在React中的事件綁定機制中疹吃,事件名為駝峰式格式,事件的值是一個Function

  • React中的事件處理函數的語法格式為onClick= { function }西雀,可以將該函數抽離出去萨驶,與render()函數同級,如下:


render () {

  return <div>

    // 事件的值直接是一個function 匿名函數

    <button onClick= { function () { console.log('按鈕點擊事件觸發(fā)') } }>按鈕</button>

    // 注意此處函數引用不能給方法帶小括號艇肴,帶上小括號的意思是自執(zhí)行函數腔呜;不過目前看來參數是個問題

    <button onClick= { this.myFunction }>按鈕</button>

  </div>

}

// 這是一個實例方法

myFunction () {

  console.log('按鈕點擊事件觸發(fā)')

}

  • 用的最多的事件綁定形式為:(是由于箭頭函數是個匿名函數,注意this的指向就行)

render () {

  return <div>

    <button onClick= { () => this.myFunction('傳參') }>按鈕</button>

  </div>

}

// 事件處理函數需要定義為一個箭頭函數再悼,然后復制給函數名稱

myFunction = (arg) => {

  console.log( '按鈕點擊事件觸發(fā)核畴,參數為:'+ arg )

}


// 一個完整的構組件的代碼

import React from 'react'

export default class BindEvent extends React.Component {

  construcroe () {

    super ()

    this.state= {

      msg: 'hahaha',

    }

  }

  render() {

    return <div>

      <button onClick= { () => this.show('參數1', '參數2') }>按鈕</button>

    </div>

  }

  show = (arg1, arg2) => {

    console.log( '觸發(fā)點擊事件--'+ arg1+ arg2 )

  }

}

3.9.使用this.setState修改state上的數據

3.9.1 實現點擊按鈕,操作state中的數據


  show = (arg1, arg2) => {

    console.log( '觸發(fā)點擊事件--'+ arg1+ arg2 )

    // React中冲九,使用setState()方法改變state中的數據狀態(tài)值谤草,并自動進行頁面重新渲染,而直接 this.state.msg 形式修改數據后不會重新渲染娘侍;

    this.setState({

      msg: '12345',

    });

  }

3.10.this.setState的兩個注意點

  • this.setState({})中咖刃,只會把對應的數據狀態(tài)更新,而不會覆蓋其他的數據狀態(tài)憾筏;

  • this.setState({})中的代碼時異步執(zhí)行的嚎杨,若在this.setState({})執(zhí)行完畢后,又想立即拿到最新值氧腰,不能使用this.state.msg直接去取枫浙,而是使用this.setState({},callback)刨肃,用回調函數來獲取最新的狀態(tài)值;

3.11.React中綁定文本框與State中的值

默認情況下箩帚,在React中真友,如果頁面的表單元素綁定了 state 上的數據的狀態(tài)值,那么每當 state 上的狀態(tài)值變換紧帕,必然會自動把最新的狀態(tài)值同步到頁面上:

單項數據綁定:狀態(tài)值變化->自動更新頁面數據盔然;

若是UI頁面的文本框內容變化時,需要將變化同步到 state 中去是嗜,此時React中沒有這種自動同步機制愈案,需要程序員手動監(jiān)聽文本框內容的變化 onChange 事件,在 onChange 事件中拿到最新的文本框的值(方案1:使用e事件進行獲榷焯隆站绪;方案2:使用ref屬性獲取元素 ),再通過手動調用 this.setState({})手動把值同步到 state 中丽柿;


  render() {

    return <div>

      <button onClick= { () => this.show('參數1', '參數2') }>按鈕</button>

      {/* 若直接把文本框的 value 屬性恢准,綁定到了state 的數據狀態(tài)值,而不提供 onChange 處理函數甫题,

      得到的文本框是一個只讀的文本框馁筐;當文本框綁定 value 值后,要么提供一個 readyOnly 坠非,要么提供

      一個 onChange 處理函數 */}

      {/* <input type= "text" style= { {width: '100%'} } value= {this.state.msg} readOnly /> */}

      <input type= "text" style= { {width: '100%'} } value= {this.state.msg} onChange= { (e) => this.changeEvent(e) } ref= "txt" />

    </div>

  }

  // 每當文本框內容變換時眯漩,必將會調用這個函數

  changeEvent= (e) => {

    console.log('文本框內容變換時觸發(fā)')

    // 方案1:使用`e`事件進行獲取

    // console.log(e.target.value)

    // 方案2:使用`ref`屬性獲取元素

    console.log(this.refs.txt.value)

    // 調用 this.setState({ }) 改變 state 中的數據的狀態(tài)值

    const newVal= e.target.value;

    this.setState({

      msg: newVal,

    })

  }

3.12.拓展-Vue中實例的生命周期

每個組件的實例,從 創(chuàng)建->運行->銷毀 這個過程中麻顶,這些事件就叫做組件的生命周期函數赦抖;分析對比 VueReact 的生命周期函數辅肾;

3.12.2 Vue 組件的生命周期函數

參考Vue官方文檔中的Vue聲明周期函數的圖示進行分析:Vue生命周期圖示

3.12.2.1 Vue 組件的創(chuàng)建階段

  1. Init Event & LifeCycle:初始化Vue事件Vue的聲明周期函數队萤;

  2. beforeCreate:這是組件創(chuàng)建階段的第一個聲明周期函數,此時組件的datamethods以及頁面的DOM結構都還沒有初始化矫钓,因而什么都做不了要尔;

  3. Init injection & reactivity:初始化datamethods中的數據和方法;

  4. created:這個是組件創(chuàng)建階段的第二個生命周期函數新娜,此時組件的datamethods已經可用了赵辕,但是頁面還沒有渲染出效果來,因而在這個生命周期中常常會發(fā)起 Ajax 請求概龄;

  5. Has 'el' option?:判斷傳入的Vue對象是否有el还惠,有的話就進行編譯控制區(qū)域的代碼;沒有的話就等待私杜,直到vm.$mounted(el)手動渲染蚕键,也進行編譯控制區(qū)域的代碼 (把 data 上的數據拿到救欧,并解析執(zhí)行模板結構中的指令,當所有的指令解析完畢锣光,那么模板頁面就渲染到內存中了笆怠,此時模板頁面還沒有掛載到頁面上,僅僅存放在內存中誊爹,因而用戶還看不到效果)蹬刷;

  6. beforMount:這是組件創(chuàng)建階段的第三個聲明周期函數,此時模板結構在內存中已經編譯完成,還沒有真正渲染到頁面中,此時看到的只是模板頁面赁豆,沒有進行數據的渲染;

  7. Create vm.$el and replace 'el' with it:這一步正在把內存中渲染好的模板結構替換到頁面上;

  8. mounted:這個是組件創(chuàng)建階段的第四個生命周期函數兽赁,此時頁面已經真正的渲染好了状答,用戶已經可以看到真實的頁面數據;當這個生命周期函數執(zhí)行完刀崖,組件的創(chuàng)建階段就完成了惊科,進入到了組件的運行階段;若大家用到了一些第三方的UI插件亮钦,而且這些插件需要被初始化馆截,那么必須在mounted中進行初始化插件;

3.12.2.2 Vue 組件的運行階段

按需根據 data 數據的變化蜂莉,有選擇性的執(zhí)行 0 到 N 次蜡娶;

  1. beforUpdate:在這個生命周期函數中,數據是最新的數據映穗,而在頁面中呈現出的數據還是舊數據窖张;

  2. Virtual DOM re-render and patch:這個階段是根據最新的 data 數據,重新渲染模板結構到內存中蚁滋,并把渲染好的模板結構替換到頁面上宿接;

  3. updated:在這個生命周期函數中,頁面已經完成了更新辕录,data數據是最新的睦霎,頁面中呈現的數據也是最新的;

3.12.2.3 Vue 組件的銷毀階段

  1. beforeDestroy:這個生命周期函數會在 vm.$destroy()被調用時觸發(fā)走诞,只是表示改組件即將被銷毀副女;此時組件還是可用的,比如其中的datamethods等數據方法蚣旱,可正常訪問肮塞;

  2. Teardown watchers ,child components and event listeners:執(zhí)行銷毀處理操作襟齿,清理 檢測器 子組件 事件監(jiān)聽器

  3. destroyed:在這個生命周期函數中枕赵,組件已經完成銷毀猜欺,其中的datamethods等數據方法都不可訪問使用;

3.13.拓展-Vue中實例的生命周期2(見上方)

3.14.快速梳理React的組件生命周期函數圖

參考React官方文檔中的React生命周期函數的圖示進行分析:React生命周期圖示

3.14.1 React 組件的創(chuàng)建階段

永遠只執(zhí)行一次拷窜;

  1. componentWillMount

  2. render

  3. componentDidMount

3.14.2 React 組件的運行階段

按需根據 props 屬性或 state 狀態(tài)的改變开皿,有選擇性的執(zhí)行 0 到多次;

  1. componentWillReceiveProps

  2. shouldcomponentUpdate

  3. componentWillUpdate

  4. render

  5. componentDidUpdate

3.14.3 React 組件的銷毀階段

永遠只執(zhí)行一次篮昧;

  1. componentWillUnmount
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末赋荆,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子懊昨,更是在濱河造成了極大的恐慌窄潭,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件酵颁,死亡現場離奇詭異嫉你,居然都是意外死亡,警方通過查閱死者的電腦和手機躏惋,發(fā)現死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門幽污,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人簿姨,你說我怎么就攤上這事距误。” “怎么了扁位?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵准潭,是天一觀的道長。 經常有香客問我域仇,道長惋鹅,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任殉簸,我火速辦了婚禮闰集,結果婚禮上,老公的妹妹穿的比我還像新娘般卑。我一直安慰自己武鲁,他們只是感情好,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布蝠检。 她就那樣靜靜地躺著沐鼠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上饲梭,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天乘盖,我揣著相機與錄音,去河邊找鬼憔涉。 笑死订框,一個胖子當著我的面吹牛,可吹牛的內容都是我干的兜叨。 我是一名探鬼主播穿扳,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼国旷!你這毒婦竟也來了矛物?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤跪但,失蹤者是張志新(化名)和其女友劉穎履羞,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體屡久,經...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡忆首,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了涂身。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡搓蚪,死狀恐怖蛤售,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情妒潭,我是刑警寧澤悴能,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站雳灾,受9級特大地震影響漠酿,放射性物質發(fā)生泄漏。R本人自食惡果不足惜谎亩,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一炒嘲、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧匈庭,春花似錦夫凸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春鸽扁,著一層夾襖步出監(jiān)牢的瞬間蒜绽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工桶现, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留躲雅,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓巩那,卻偏偏與公主長得像吏夯,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子即横,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內容

  • 從零搭建React全家桶框架教程筆記(一) 傳送門:從零搭建React全家桶框架教程 目錄 寫在前面 | 說明...
    Haleng閱讀 6,953評論 2 8
  • ReactJs小書筆記(一) ReactJs小書官方文檔:傳送門 1 react簡介 React.js 不是一個框...
    Haleng閱讀 687評論 0 0
  • React組件學習筆記——慕課網 React組件慕課網視頻:傳送門 第1章 初識React 1.1 React基本...
    Haleng閱讀 558評論 0 0
  • [toc] REACT react :1.用來構建用戶界面的 JAVASCRIPT 庫2.react 專注于視圖層...
    撥開云霧0521閱讀 1,444評論 0 1
  • RAC有一個主要的優(yōu)點噪生,就是提供一個單一的,統(tǒng)一的方法去處理異步的行為东囚,包括delegate方法跺嗽,blocks回調...
    csp閱讀 249評論 0 0